Compare commits

..

20 Commits
v33.0 ... v30.1

Author SHA1 Message Date
Bo Chen
93d7e01b41 build: Release v30.1 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 16:41:05 -07:00
Bo Chen
4fe593e12d tests: Enable live-upgrade tests based on v30.0
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
4203a61947 vmm: Remove unnecessary parentheses (beta 1.69 clippy check)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
e397e739bf tests: Extend '_test_macvtap()' with reboot
In this way, we can cover the scenario where a VM with hotplugged net
device using FDs can work properly with reboot.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
2724edd1e5 vmm: Add valid FDs for TAP devices to 'VmConfig::preserved_fds'
In this way, valid FDs for TAP devices will be closed when the holding
VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
269844da73 vmm: Add unit test for 'VmConfig::preserved_fds'
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
a299a10874 vmm: Implement Clone and Drop for VmConfig
The custom 'clone' duplicates 'preserved_fds' so that the validation
logic can be safely carried out on the clone of the VmConfig.

The custom 'drop' ensures 'preserved_fds' are safely closed when the
holding VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
015941e294 vmm: config: Extend 'VmConfig' with 'preserved_fds'
Preserved FDs are the ones that share the same life-time as its holding
VmConfig instance, such as FDs for creating TAP devices.

Preserved FDs will stay open as long as the holding VmConfig instance is
valid, and will be closed when the holding VmConfig instance is destroyed.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
ca6fe2a98e Revert "vmm: config: Implement Clone for NetConfig"
This reverts commit ea4a95c4f6.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
f4090b0196 Revert "vmm: config: Close FDs for TAP devices that are provided to VM"
This reverts commit b14427540b.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
3432c0ce5e Revert "vmm: config: Don't close reserved FDs from NetConfig::drop()"
This reverts commit 0110fb4edc.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
ec70af1606 Revert "vmm: config: Avoid closing invalid FDs from 'test_net_parsing()'"
This reverts commit 0567def931.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Bo Chen
bb0d82c365 Revert "vmm: config: Replace use of memfd_create with fd pointing to /dev/null"
This reverts commit 46066d6ae1.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Alyssa Ross
2d98a16d05 vmm: only touch the tty flags if it's being used
When neither serial nor console are connected to the tty,
cloud-hypervisor shouldn't touch the tty at all.  One way in which
this is annoying is that if I am running cloud-hypervisor without it
using my terminal, I expect to be able to suspend it with ^Z like any
other process, but that doesn't work if it's put the terminal into raw
mode.

Instead of putting the tty into raw mode when a VM is created or
restored, do it when a serial or console device is created.  Since we
now know it can't be put into raw mode until the Vm object is created,
we can move setting it back to canon mode into the drop handler for
that object, which should always be run in normal operation.  We still
also put the tty into canon mode in the SIGTERM / SIGINT handler, but
check whether the tty was actually used, rather than whether stdin is
a tty.  This requires passing on_tty around as an atomic boolean.

I explored more of an abstraction over the tty — having an object that
encapsulated stdout and put the tty into raw mode when initialized and
into canon mode when dropped — but it wasn't practical, mostly due to
the special requirements of the signal handler.  I also investigated
whether the SIGWINCH listener process could be used here, which I
think would have worked but I'm hesitant to involve it in serial
handling as well as conosle handling.

There's no longer a check for whether the file descriptor is a tty
before setting it into canon mode — it's redundant, because if it's
not a tty it just won't respond to the ioctl.

Tested by shutting down through the API, SIGTERM, and an error
injected after setting raw mode.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
cd1a645421 vmm: don't redundantly set the TTY to canon mode
If the VM is shut down, either it's going to be started again, in
which case we still want to be in raw mode, or the process is about to
exit, in which case canon mode will be set at the end of main.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
4485210de5 vmm: only use KVM_ARM_VCPU_PMU_V3 if available
Having PMU in guests isn't critical, and not all hardware supports
it (e.g. Apple Silicon).

CpuManager::init_pmu already has a fallback for if PMU is not
supported by the VCPU, but we weren't getting that far, because we
would always try to initialise the VCPU with KVM_ARM_VCPU_PMU_V3, and
then bail when it returned with EINVAL.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Alyssa Ross
0aa858c266 virtio-devices: seccomp: add vhost-user syscalls
Cloud Hypervisor's vhost-user implementation will reconnect if it gets
disconnected from the backend.  That means connections happen inside
the vhost-user seccomp sandbox, so all syscalls used in reconnecting
have to be allowed in that sandbox.

clock_nanosleep is used by Glibc, and nanosleep is used by musl.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-04-18 11:47:31 -07:00
Bo Chen
499e8433c3 vmm: Ignore and warn TAP FDs sent via the HTTP request body
Valid FDs can only be sent from another process via `SCM_RIGHTS`.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 11:47:31 -07:00
Omer Faruk Bayram
ff27b00f5a ch-remote: fixed ShutdownVmm and Shutdown commands
Fixed `ShutdownVmm` and `Shutdown` commands to call the correct API
endpoint.

Signed-off-by: Omer Faruk Bayram <omer.faruk@sartura.hr>
2023-04-18 11:47:31 -07:00
Hao Xu
d09af361bc virtio-devices: Reset offset properly upon unmap for virtio-fs.
We should reset the offset to 0, when asked to remove the whole dax
mapping.

Signed-off-by: Hao Xu <howeyxu@tencent.com>
2023-04-18 11:47:31 -07:00
120 changed files with 2298 additions and 5156 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- stable - stable
- beta - beta
- nightly - nightly
- "1.64" - "1.62"
target: target:
- x86_64-unknown-linux-gnu - x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl - x86_64-unknown-linux-musl
@@ -42,9 +42,6 @@ jobs:
- name: Build (default features + tdx) - name: Build (default features + tdx)
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks 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) - name: Build (default features + guest_debug)
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks

View File

@@ -7,10 +7,6 @@ on:
pull_request: pull_request:
paths: resources/Dockerfile paths: resources/Dockerfile
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs: jobs:
main: main:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -24,19 +20,19 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v1
- name: Login to ghcr - name: Login to DockerHub
uses: docker/login-action@v2 if: ${{ github.event_name == 'push' }}
uses: docker/login-action@v1
with: with:
registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKERHUB_USERNAME }}
username: ${{ github.actor }} password: ${{ secrets.DOCKERHUB_TOKEN }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta - name: Docker meta
id: meta id: meta
uses: docker/metadata-action@v4 uses: docker/metadata-action@v3
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # list of Docker images to use as base name for tags
images: cloudhypervisor/dev
# generate Docker tags based on the following events/attributes # generate Docker tags based on the following events/attributes
tags: | tags: |
type=raw,value={{date 'YYYYMMDD'}}-0 type=raw,value={{date 'YYYYMMDD'}}-0

View File

@@ -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

View File

@@ -16,29 +16,29 @@ jobs:
- name: Install Rust toolchain (x86_64-unknown-linux-gnu) - name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.67.1" toolchain: "1.62"
target: x86_64-unknown-linux-gnu target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl) - name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.67.1" toolchain: "1.62"
target: x86_64-unknown-linux-musl target: x86_64-unknown-linux-musl
- name: Build - name: Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.67.1" toolchain: "1.62"
command: build command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu
- name: Static Build - name: Static Build
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
toolchain: "1.67.1" toolchain: "1.62"
command: build command: build
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl
- name: Install Rust toolchain (aarch64-unknown-linux-musl) - name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1 uses: actions-rs/toolchain@v1
with: with:
toolchain: "1.67.1" toolchain: "1.62"
target: aarch64-unknown-linux-musl target: aarch64-unknown-linux-musl
override: true override: true
- name: Create Release - name: Create Release

1228
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "33.0.0" version = "30.1.0"
authors = ["The Cloud Hypervisor Authors"] authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
default-run = "cloud-hypervisor" default-run = "cloud-hypervisor"
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# a.) A dependency requires it, # a.) A dependency requires it,
# b.) If we want to use a new feature and that MSRV is at least 6 months old, # 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. # c.) There is a security issue that is addressed by the toolchain update.
rust-version = "1.64" rust-version = "1.62"
[profile.release] [profile.release]
lto = true lto = true
@@ -29,7 +29,7 @@ strip = false
debug = true debug = true
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
api_client = { path = "api_client" } api_client = { path = "api_client" }
argh = "0.1.9" argh = "0.1.9"
dhat = { version = "0.3.2", optional = true } dhat = { version = "0.3.2", optional = true }
@@ -40,34 +40,31 @@ libc = "0.2.139"
log = { version = "0.4.17", features = ["std"] } log = { version = "0.4.17", features = ["std"] }
option_parser = { path = "option_parser" } option_parser = { path = "option_parser" }
seccompiler = "0.3.0" seccompiler = "0.3.0"
serde_json = "1.0.96" serde_json = "1.0.93"
signal-hook = "0.3.15" signal-hook = "0.3.14"
thiserror = "1.0.40" thiserror = "1.0.38"
tpm = { path = "tpm"} tpm = { path = "tpm"}
tracer = { path = "tracer" } tracer = { path = "tracer" }
vmm = { path = "vmm" } vmm = { path = "vmm" }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"
vm-memory = "0.11.0" vm-memory = "0.10.0"
zbus = { version = "3.11.1", optional = true }
# List of patched crates # List of patched crates
[patch.crates-io] [patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" } 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" } kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" } versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
[dev-dependencies] [dev-dependencies]
dirs = "5.0.0" dirs = "4.0.0"
net_util = { path = "net_util" } net_util = { path = "net_util" }
once_cell = "1.17.1" once_cell = "1.17.1"
serde_json = "1.0.96" serde_json = "1.0.93"
test_infra = { path = "test_infra" } test_infra = { path = "test_infra" }
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
[features] [features]
default = ["kvm"] default = ["kvm"]
dbus_api = ["zbus", "vmm/dbus_api"]
dhat-heap = ["dhat"] # For heap profiling dhat-heap = ["dhat"] # For heap profiling
guest_debug = ["vmm/guest_debug"] guest_debug = ["vmm/guest_debug"]
kvm = ["vmm/kvm"] kvm = ["vmm/kvm"]

View File

@@ -113,7 +113,7 @@ Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.) edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
Binary builds of the firmware files are available for the latest release of Binary builds of the firmware files are available for the latest release of
[Rust Hypervisor [Rust Hyperivor
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest) Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest)
and [our edk2 and [our edk2
repository](https://github.com/cloud-hypervisor/edk2/releases/latest) repository](https://github.com/cloud-hypervisor/edk2/releases/latest)
@@ -124,7 +124,7 @@ may be required.
### Firmware Booting ### Firmware Booting
Cloud Hypervisor supports booting disk images containing all needed components Cloud Hypervisor supports booting disk images containing all needed components
to run cloud workloads, a.k.a. cloud images. to run cloud workloads, a.k.a. cloud images.
The following sample commands will download an Ubuntu Cloud image, converting The following sample commands will download an Ubuntu Cloud image, converting
it into a format that Cloud Hypervisor can use and a firmware to boot the image it into a format that Cloud Hypervisor can use and a firmware to boot the image
@@ -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 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). `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 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 is only necessary to add this disk image on the first boot.
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.
```shell ```shell
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor $ sudo setcap cap_net_admin+ep ./cloud-hypervisor
@@ -181,7 +178,7 @@ To build the kernel:
```shell ```shell
# Clone the Cloud Hypervisor Linux branch # Clone the Cloud Hypervisor Linux branch
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.2 linux-cloud-hypervisor $ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.1.6 linux-cloud-hypervisor
$ pushd linux-cloud-hypervisor $ pushd linux-cloud-hypervisor
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64 # Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64 $ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
@@ -375,8 +372,8 @@ are all equal and welcome means of contribution. See the
## Slack ## Slack
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI), Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI)
[join us on Slack](https://cloud-hypervisor.slack.com/), and [participate in our community activities](https://cloud-hypervisor.slack.com/archives/C04R5DUQVBN). and [join us on Slack](https://cloud-hypervisor.slack.com/).
## Mailing list ## Mailing list

View File

@@ -9,18 +9,18 @@ default = []
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.139" 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" log = "0.4.17"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
thiserror = "1.0.40" thiserror = "1.0.38"
uuid = "1.3.4" uuid = "1.3.0"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" 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" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] } vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }

View File

@@ -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, 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, PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
}; };
use std::fs;
use std::path::Path;
use vm_fdt::{FdtWriter, FdtWriterResult}; use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion}; 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. // NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
// This is a value for uniquely identifying the FDT node containing the first vCPU. // 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. // 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. // Read the documentation specified when appending the root node to the FDT.
const ADDRESS_CELLS: u32 = 0x2; const ADDRESS_CELLS: u32 = 0x2;
const SIZE_CELLS: u32 = 0x2; const SIZE_CELLS: u32 = 0x2;
@@ -87,97 +81,6 @@ pub enum Error {
} }
type Result<T> = result::Result<T, 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. /// Creates the flattened device tree for this aarch64 VM.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>( 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(); 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) { for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
let cpu_name = format!("cpu@{cpu_id:x}"); let cpu_name = format!("cpu@{cpu_id:x}");
let cpu_node = fdt.begin_node(&cpu_name)?; 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("reg", (mpidr & 0x7FFFFF) as u32)?;
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?; 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. // Add `numa-node-id` property if there is any numa config.
if numa_nodes.len() > 1 { if numa_nodes.len() > 1 {
for numa_node_idx in 0..numa_nodes.len() { for numa_node_idx in 0..numa_nodes.len() {
@@ -346,36 +186,6 @@ fn create_cpu_nodes(
fdt.end_node(cpu_node)?; 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 { if let Some(topology) = vcpu_topology {
let (threads_per_core, cores_per_package, packages) = topology; let (threads_per_core, cores_per_package, packages) = topology;
let cpu_map_node = fdt.begin_node("cpu-map")?; let cpu_map_node = fdt.begin_node("cpu-map")?;
@@ -450,86 +260,32 @@ fn create_memory_node(
fdt.end_node(memory_node)?; fdt.end_node(memory_node)?;
} }
} else { } else {
// Note: memory regions from "GuestMemory" are sorted and non-zero sized. let last_addr = guest_mem.last_addr().raw_value();
let ram_regions = { if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
let mut ram_regions = Vec::new(); // Case 1: all RAM is under the hole
let mut current_start = guest_mem let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
.iter() let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
.next() let memory_node = fdt.begin_node("memory")?;
.map(GuestMemoryRegion::start_addr) fdt.property_string("device_type", "memory")?;
.expect("GuestMemory must have one memory region at least") fdt.property_array_u64("reg", &mem_reg_prop)?;
.raw_value(); fdt.end_node(memory_node)?;
let mut current_end = current_start; } else {
// Case 2: RAM is split by the hole
for (start, size) in guest_mem // Region 1: RAM before the hole
.iter() let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
.map(|m| (m.start_addr().raw_value(), m.len())) - super::layout::RAM_START.raw_value();
{ let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
if current_end == start { let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
// This zone is continuous with the previous one.
current_end += size;
} else {
ram_regions.push((current_start, current_end));
current_start = start;
current_end = start + size;
}
}
ram_regions.push((current_start, current_end));
ram_regions
};
if ram_regions.len() > 2 {
panic!(
"There should be up to two non-continuous regions, devidided by the
gap at the end of 32bit address space."
);
}
// Create the memory node for memory region before the gap
{
let (first_region_start, first_region_end) = ram_regions
.first()
.expect("There should be at last one memory region");
let ram_start = super::layout::RAM_START.raw_value();
let mem_32bit_reserved_start = super::layout::MEM_32BIT_RESERVED_START.raw_value();
if !((first_region_start <= &ram_start)
&& (first_region_end > &ram_start)
&& (first_region_end <= &mem_32bit_reserved_start))
{
panic!(
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
);
}
let mem_size = first_region_end - ram_start;
let mem_reg_prop = [ram_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_start);
let memory_node = fdt.begin_node(&memory_node_name)?; let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?; fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?; fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?; fdt.end_node(memory_node)?;
}
// Create the memory map entry for memory region after the gap if any // Region 2: RAM after the hole
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) { let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
let ram_64bit_start = super::layout::RAM_64BIT_START.raw_value(); let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
let memory_node_name =
if second_region_start != &ram_64bit_start { format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
panic!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
);
}
let mem_size = second_region_end - ram_64bit_start;
let mem_reg_prop = [ram_64bit_start, mem_size];
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
let memory_node = fdt.begin_node(&memory_node_name)?; let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?; fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?; fdt.property_array_u64("reg", &mem_reg_prop)?;

View File

@@ -19,9 +19,7 @@ use std::collections::HashMap;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug; use std::fmt::Debug;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic}; use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
pub const _NSIG: i32 = 65;
/// Errors thrown while configuring aarch64 system. /// Errors thrown while configuring aarch64 system.
#[derive(Debug)] #[derive(Debug)]
@@ -83,8 +81,8 @@ pub fn configure_vcpu(
Ok(mpidr) Ok(mpidr)
} }
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> { pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
vec![ let mut regions = vec![
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices // 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
( (
GuestAddress(0), GuestAddress(0),
@@ -103,21 +101,39 @@ pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
layout::PCI_MMCONFIG_SIZE as usize, layout::PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved, RegionType::Reserved,
), ),
// 1GiB ~ 4032 MiB: RAM before the gap ];
(
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
// RAM space
// Case1: guest memory fits before the gap
if size <= ram_32bit_space_size {
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
// Case2: guest memory extends beyond the gap
} else {
// Push memory before the gap
regions.push((
layout::RAM_START, layout::RAM_START,
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize, ram_32bit_space_size as usize,
RegionType::Ram, RegionType::Ram,
), ));
// 4GiB ~ inf: RAM after the gap // Other memory is placed after 4GiB
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram), regions.push((
// Add the 32-bit reserved memory hole as a reserved region layout::RAM_64BIT_START,
( (size - ram_32bit_space_size) as usize,
layout::MEM_32BIT_RESERVED_START, RegionType::Ram,
layout::MEM_32BIT_RESERVED_SIZE as usize, ));
RegionType::Reserved, }
),
] // Add the 32-bit reserved memory hole as a reserved region
regions.push((
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_RESERVED_SIZE as usize,
RegionType::Reserved,
));
regions
} }
/// Configures the system and should be called once per vm before starting vcpu threads. /// Configures the system and should be called once per vm before starting vcpu threads.
@@ -180,8 +196,11 @@ pub fn initramfs_load_addr(
} }
} }
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 { pub fn get_host_cpu_phys_bits() -> u8 {
let host_cpu_phys_bits = hypervisor.get_host_ipa_limit().try_into().unwrap(); // 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 { if host_cpu_phys_bits == 0 {
// Host kernel does not support `get_host_ipa_limit`, // Host kernel does not support `get_host_ipa_limit`,
// we return the default value 40 here. // we return the default value 40 here.
@@ -196,12 +215,26 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn test_arch_memory_regions_dram() { fn test_arch_memory_regions_dram_2gb() {
let regions = arch_memory_regions(); let regions = arch_memory_regions((1usize << 31) as u64); //2GB
assert_eq!(5, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!((1usize << 31), regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[4].2);
}
#[test]
fn test_arch_memory_regions_dram_4gb() {
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
assert_eq!(6, regions.len()); assert_eq!(6, regions.len());
assert_eq!(layout::RAM_START, regions[3].0); assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!(ram_32bit_space_size, regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2); assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[5].2); assert_eq!(RegionType::Reserved, regions[5].2);
assert_eq!(RegionType::Ram, regions[4].2); assert_eq!(RegionType::Ram, regions[4].2);
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
} }
} }

View File

@@ -1,17 +1,18 @@
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved. // Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// AArch64 system register encoding: ///
// See https://developer.arm.com/documentation/ddi0487 (chapter D12) /// AArch64 system register encoding:
// /// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0 ///
// +----------+---+-----+-----+-----+-----+-----+----+ /// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt | /// +----------+---+-----+-----+-----+-----+-----+----+
// +----------+---+-----+-----+-----+-----+-----+----+ /// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
// /// +----------+---+-----+-----+-----+-----+-----+----+
// Notes: ///
// - L and Rt are reserved as implementation defined fields, ignored. /// Notes:
/// - L and Rt are reserved as implementation defined fields, ignored.
///
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22; const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
const SYSREG_OP0_SHIFT: u32 = 19; const SYSREG_OP0_SHIFT: u32 = 19;
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19; const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;

View File

@@ -82,7 +82,7 @@ pub mod aarch64;
pub use aarch64::{ pub use aarch64::{
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt, arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::IRQ_BASE, uefi, EntryPoint, _NSIG, layout::IRQ_BASE, uefi, EntryPoint,
}; };
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
@@ -92,7 +92,7 @@ pub mod x86_64;
pub use x86_64::{ pub use x86_64::{
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid, arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE, get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG, layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint,
}; };
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`. /// Safe wrapper for `sysconf(_SC_PAGESIZE)`.

View File

@@ -16,7 +16,7 @@ use crate::GuestMemoryMmap;
use crate::InitramfsConfig; use crate::InitramfsConfig;
use crate::RegionType; use crate::RegionType;
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX}; 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::bootparam::boot_params;
use linux_loader::loader::elf::start_info::{ use linux_loader::loader::elf::start_info::{
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info, hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
@@ -53,8 +53,6 @@ const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5; const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
pub const _NSIG: i32 = 65;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
/// Specifies the entry point address where the guest must start /// Specifies the entry point address where the guest must start
/// executing code, as well as which of the supported boot protocols /// executing code, as well as which of the supported boot protocols
@@ -210,6 +208,7 @@ impl From<Error> for super::Error {
} }
} }
#[allow(clippy::upper_case_acronyms)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum CpuidReg { pub enum CpuidReg {
EAX, EAX,
@@ -775,13 +774,6 @@ pub fn configure_vcpu(
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id)); CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id)); CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
// Set ApicId in cpuid for each vcpu
// SAFETY: get host cpuid when eax=1
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
cpu_ebx &= 0xffffff;
cpu_ebx |= (id as u32) << 24;
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation // The TSC frequency CPUID leaf should not be included when running with HyperV emulation
if !kvm_hyperv { if !kvm_hyperv {
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? { if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
@@ -834,29 +826,47 @@ pub fn configure_vcpu(
/// These should be used to configure the GuestMemory structure for the platform. /// These should be used to configure the GuestMemory structure for the platform.
/// For x86_64 all addresses are valid from the start of the kernel except a /// For x86_64 all addresses are valid from the start of the kernel except a
/// carve out at the end of 32bit address space. /// carve out at the end of 32bit address space.
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> { pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
vec![ let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START
// 0 GiB ~ 3GiB: memory before the gap .checked_add(layout::MEM_32BIT_DEVICES_SIZE)
( .expect("32-bit reserved region is too large");
let requested_memory_size = GuestAddress(size);
let mut regions = Vec::new();
// case1: guest memory fits before the gap
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
// case2: guest memory extends beyond the gap
} else {
// push memory before the gap
regions.push((
GuestAddress(0), GuestAddress(0),
layout::MEM_32BIT_RESERVED_START.raw_value() as usize, layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
RegionType::Ram, RegionType::Ram,
), ));
// 4 GiB ~ inf: memory after the gap regions.push((
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram), layout::RAM_64BIT_START,
// 3 GiB ~ 3712 MiB: 32-bit device memory hole requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize,
( RegionType::Ram,
layout::MEM_32BIT_RESERVED_START, ));
layout::MEM_32BIT_DEVICES_SIZE as usize, }
RegionType::SubRegion,
), // Add the 32-bit device memory hole as a sub region.
// 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole regions.push((
( layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE), layout::MEM_32BIT_DEVICES_SIZE as usize,
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize, RegionType::SubRegion,
RegionType::Reserved, ));
),
] // Add the 32-bit reserved memory hole as a sub region.
regions.push((
reserved_memory_gap_start,
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
RegionType::Reserved,
));
regions
} }
/// Configures the system and should be called once per vm before starting vcpu threads. /// Configures the system and should be called once per vm before starting vcpu threads.
@@ -954,102 +964,30 @@ fn configure_pvh(
// Create the memory map entries. // Create the memory map entries.
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM); add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
// Merge continuous memory regions into one region. let mem_end = guest_mem.last_addr();
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
let ram_regions = {
let mut ram_regions = Vec::new();
let mut current_start = guest_mem
.iter()
.next()
.map(GuestMemoryRegion::start_addr)
.expect("GuestMemory must have one memory region at least")
.raw_value();
let mut current_end = current_start;
for (start, size) in guest_mem
.iter()
.map(|m| (m.start_addr().raw_value(), m.len()))
{
if current_end == start {
// This zone is continuous with the previous one.
current_end += size;
} else {
ram_regions.push((current_start, current_end));
current_start = start;
current_end = start + size;
}
}
ram_regions.push((current_start, current_end));
ram_regions
};
if ram_regions.len() > 2 {
error!(
"There should be up to two non-continuous regions, devidided by the
gap at the end of 32bit address space (e.g. between 3G and 4G)."
);
return Err(super::Error::MemmapTableSetup);
}
// Create the memory map entry for memory region before the gap
{
let (first_region_start, first_region_end) =
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
let high_ram_start = layout::HIGH_RAM_START.raw_value();
let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
if !((first_region_start <= &high_ram_start)
&& (first_region_end > &high_ram_start)
&& (first_region_end <= &mem_32bit_reserved_start))
{
error!(
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
);
return Err(super::Error::MemmapTableSetup);
}
info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
high_ram_start, first_region_end
);
if mem_end < layout::MEM_32BIT_RESERVED_START {
add_memmap_entry( add_memmap_entry(
&mut memmap, &mut memmap,
high_ram_start, layout::HIGH_RAM_START.raw_value(),
first_region_end - high_ram_start, mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
E820_RAM, E820_RAM,
); );
} } else {
// Create the memory map entry for memory region after the gap if any
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
if second_region_start != &ram_64bit_start {
error!(
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
second_region_start, ram_64bit_start
);
return Err(super::Error::MemmapTableSetup);
}
info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
ram_64bit_start, second_region_end
);
add_memmap_entry( add_memmap_entry(
&mut memmap, &mut memmap,
ram_64bit_start, layout::HIGH_RAM_START.raw_value(),
second_region_end - ram_64bit_start, layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
E820_RAM, E820_RAM,
); );
if mem_end > layout::RAM_64BIT_START {
add_memmap_entry(
&mut memmap,
layout::RAM_64BIT_START.raw_value(),
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
E820_RAM,
);
}
} }
add_memmap_entry( add_memmap_entry(
@@ -1139,7 +1077,7 @@ pub fn initramfs_load_addr(
Ok(aligned_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 // SAFETY: call cpuid with valid leaves
unsafe { unsafe {
let leaf = x86_64::__cpuid(0x8000_0000); let leaf = x86_64::__cpuid(0x8000_0000);
@@ -1148,7 +1086,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. // Some physical address bits may become reserved when the feature is enabled.
// See AMD64 Architecture Programmer's Manual Volume 2, Section 7.10.1 // See AMD64 Architecture Programmer's Manual Volume 2, Section 7.10.1
let reduced = if leaf.eax >= 0x8000_001f 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).eax & 0x1 != 0
{ {
(x86_64::__cpuid(0x8000_001f).ebx >> 6) & 0x3f (x86_64::__cpuid(0x8000_001f).ebx >> 6) & 0x3f
@@ -1283,8 +1223,16 @@ mod tests {
use super::*; use super::*;
#[test] #[test]
fn regions_base_addr() { fn regions_lt_4gb() {
let regions = arch_memory_regions(); let regions = arch_memory_regions(1 << 29);
assert_eq!(3, regions.len());
assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(1usize << 29, regions[0].1);
}
#[test]
fn regions_gt_4gb() {
let regions = arch_memory_regions((1 << 32) + 0x8000);
assert_eq!(4, regions.len()); assert_eq!(4, regions.len());
assert_eq!(GuestAddress(0), regions[0].0); assert_eq!(GuestAddress(0), regions[0].0);
assert_eq!(GuestAddress(1 << 32), regions[1].0); assert_eq!(GuestAddress(1 << 32), regions[1].0);
@@ -1308,10 +1256,11 @@ mod tests {
assert!(config_err.is_err()); assert!(config_err.is_err());
// Now assigning some memory that falls before the 32bit memory hole. // Now assigning some memory that falls before the 32bit memory hole.
let arch_mem_regions = arch_memory_regions(); let mem_size = 128 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter() .iter()
.filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX) .filter(|r| r.2 == RegionType::Ram)
.map(|r| (r.0, r.1)) .map(|r| (r.0, r.1))
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
@@ -1329,18 +1278,48 @@ mod tests {
) )
.unwrap(); .unwrap();
// Now assigning some memory that falls after the 32bit memory hole. // Now assigning some memory that is equal to the start of the 32bit memory hole.
let arch_mem_regions = arch_memory_regions(); let mem_size = 3328 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter() .iter()
.filter(|r| r.2 == RegionType::Ram) .filter(|r| r.2 == RegionType::Ram)
.map(|r| { .map(|r| (r.0, r.1))
if r.1 == usize::MAX { .collect();
(r.0, 128 << 20) let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
} else { configure_system(
(r.0, r.1) &gm,
} GuestAddress(0),
}) &None,
no_vcpus,
None,
None,
None,
None,
None,
)
.unwrap();
configure_system(
&gm,
GuestAddress(0),
&None,
no_vcpus,
None,
None,
None,
None,
None,
)
.unwrap();
// Now assigning some memory that falls after the 32bit memory hole.
let mem_size = 3330 << 20;
let arch_mem_regions = arch_memory_regions(mem_size);
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
.iter()
.filter(|r| r.2 == RegionType::Ram)
.map(|r| (r.0, r.1))
.collect(); .collect();
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap(); let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
configure_system( configure_system(

View File

@@ -8,18 +8,18 @@ edition = "2021"
default = [] default = []
[dependencies] [dependencies]
io-uring = "0.5.13" io-uring = "0.5.12"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
smallvec = "1.10.0" smallvec = "1.10.0"
thiserror = "1.0.40" thiserror = "1.0.38"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" } vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] } virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.8.0" virtio-queue = "0.7.0"
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-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"

View File

@@ -17,8 +17,8 @@ fn main() {
} }
// This println!() has a special behavior, as it will set the environment // 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 // Particularly, this is used from src/main.rs to display the exact
// version. // version.
println!("cargo:rustc-env=BUILD_VERSION={version}"); println!("cargo:rustc-env=BUILT_VERSION={version}");
} }

View File

@@ -6,19 +6,19 @@ edition = "2021"
[dependencies] [dependencies]
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" } acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
anyhow = "1.0.71" anyhow = "1.0.69"
arch = { path = "../arch" } arch = { path = "../arch" }
bitflags = "2.3.3" bitflags = "1.3.2"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
thiserror = "1.0.40" thiserror = "1.0.38"
tpm = { path = "../tpm" } tpm = { path = "../tpm" }
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-memory = "0.11.0" vm-memory = "0.10.0"
vm-migration = { path = "../vm-migration" } vm-migration = { path = "../vm-migration" }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"

View File

@@ -4,7 +4,7 @@
// //
use super::AcpiNotificationFlags; use super::AcpiNotificationFlags;
use acpi_tables::{aml, Aml, AmlSink}; use acpi_tables::{aml, aml::Aml};
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::time::Instant; use std::time::Instant;
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
@@ -103,11 +103,11 @@ impl BusDevice for AcpiGedDevice {
} }
impl Aml for AcpiGedDevice { impl Aml for AcpiGedDevice {
fn to_aml_bytes(&self, sink: &mut dyn AmlSink) { fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
aml::Device::new( aml::Device::new(
"_SB_.GEC_".into(), "_SB_.GEC_".into(),
vec![ vec![
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")), &aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
&aml::Name::new("_UID".into(), &"Generic Event Controller"), &aml::Name::new("_UID".into(), &"Generic Event Controller"),
&aml::Name::new( &aml::Name::new(
"_CRS".into(), "_CRS".into(),
@@ -116,19 +116,17 @@ impl Aml for AcpiGedDevice {
true, true,
self.address.0, self.address.0,
self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1, self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1,
None,
)]), )]),
), ),
&aml::OpRegion::new( &aml::OpRegion::new(
"GDST".into(), "GDST".into(),
aml::OpRegionSpace::SystemMemory, aml::OpRegionSpace::SystemMemory,
&(self.address.0 as usize), self.address.0 as usize,
&GED_DEVICE_ACPI_SIZE, GED_DEVICE_ACPI_SIZE,
), ),
&aml::Field::new( &aml::Field::new(
"GDST".into(), "GDST".into(),
aml::FieldAccessType::Byte, aml::FieldAccessType::Byte,
aml::FieldLockRule::NoLock,
aml::FieldUpdateRule::WriteAsZeroes, aml::FieldUpdateRule::WriteAsZeroes,
vec![aml::FieldEntry::Named(*b"GDAT", 8)], vec![aml::FieldEntry::Named(*b"GDAT", 8)],
), ),
@@ -165,7 +163,7 @@ impl Aml for AcpiGedDevice {
), ),
], ],
) )
.to_aml_bytes(sink); .append_aml_bytes(bytes);
aml::Device::new( aml::Device::new(
"_SB_.GED_".into(), "_SB_.GED_".into(),
vec![ vec![
@@ -189,7 +187,7 @@ impl Aml for AcpiGedDevice {
), ),
], ],
) )
.to_aml_bytes(sink) .append_aml_bytes(bytes)
} }
} }

View File

@@ -1,21 +1,18 @@
- [Cloud Hypervisor API](#cloud-hypervisor-api) - [Cloud Hypervisor API](#cloud-hypervisor-api)
- [External API](#external-api) - [External API](#external-api)
- [REST API](#rest-api) - [REST API](#rest-api)
- [REST API Location and availability](#rest-api-location-and-availability) - [Location and availability](#location-and-availability)
- [REST API Endpoints](#rest-api-endpoints) - [Endpoints](#endpoints)
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions) - [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions) - [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
- [REST API Examples](#rest-api-examples) - [REST API Examples](#rest-api-examples)
- [Create a Virtual Machine](#create-a-virtual-machine) - [Create a Virtual Machine](#create-a-virtual-machine)
- [Boot a Virtual Machine](#boot-a-virtual-machine) - [Boot a Virtual Machine](#boot-a-virtual-machine)
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information) - [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
- [Reboot a Virtual Machine](#reboot-a-virtual-machine) - [Reboot a Virtual Machine](#reboot-a-virtual-machine)
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down) - [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)
- [Command Line Interface](#command-line-interface) - [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) - [Internal API](#internal-api)
- [Goals and Design](#goals-and-design) - [Goals and Design](#goals-and-design)
- [End to End Example](#end-to-end-example) - [End to End Example](#end-to-end-example)
@@ -24,11 +21,9 @@
The Cloud Hypervisor API is made of 2 distinct interfaces: The Cloud Hypervisor API is made of 2 distinct interfaces:
1. **The External API** This is the user facing API. Users and operators 1. **The external API**. This is the user facing API. Users and operators can
can control and manage the Cloud Hypervisor through various options control and manage Cloud Hypervisor through either a REST API or a Command
including a REST API, a Command Line Interface (CLI) or a D-Bus based API, Line Interface (CLI).
which is not compiled into Cloud Hypervisor by default.
1. **The internal API**, based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/) 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 module. This API is used internally by the Cloud Hypervisor threads to
communicate between each others. 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. 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) 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) compliant. Please consult the [Cloud Hypervisor API](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. 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, The REST API is available as soon as the Cloud Hypervisor binary is started,
through a local UNIX socket. through a local UNIX socket.
@@ -70,55 +65,48 @@ Cloud Hypervisor Guest
Disk(s): None Disk(s): None
``` ```
#### REST API Endpoints ### Endpoints
The Cloud Hypervisor API exposes the following actions through its 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 | | Action | Endpoint | Request Body | Response Body | Prerequisites |
| ----------------------------------- | --------------- | ------------ | -------------------------- | ------------------ | | ----------------------------------- | --------------- | ------------ | -------------------------- | ------------------ |
| Check for the REST API availability | `/vmm.ping` | N/A | `/schemas/VmmPingResponse` | N/A | | 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 | | 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 | | Action | Endpoint | Request Body | Response Body | Prerequisites |
| ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ | | ---------------------------------- | --------------------- | --------------------------- | ------------------------ | -------------------------------- |
| Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet | | Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet |
| Delete the VM | `/vm.delete` | N/A | N/A | N/A | | Delete the VM | `/vm.delete` | N/A | N/A | N/A |
| Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted | | Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted |
| Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted | | Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted |
| Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted | | Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted |
| Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted | | Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted |
| Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted | | Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted |
| Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused | | Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused |
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused | | Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
| Perform a coredump of the VM* | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused | | Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted | | Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted | | Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted | | Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted | | Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created | | Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted | | Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted | | Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted | | Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted | | Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted | | Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
* The `vmcoredump` action is available exclusively for the `x86_64` ### REST API Examples
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.
#### REST API Examples
For the following set of examples, we assume Cloud Hypervisor is started with For the following set of examples, we assume Cloud Hypervisor is started with
the REST API available at `/tmp/cloud-hypervisor.sock`: the REST API available at `/tmp/cloud-hypervisor.sock`:
@@ -134,7 +122,7 @@ Cloud Hypervisor Guest
Disk(s): None Disk(s): None
``` ```
##### Create a Virtual Machine #### Create a Virtual Machine
We want to create a virtual machine with the following characteristics: We want to create a virtual machine with the following characteristics:
@@ -162,7 +150,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: Once the VM is created, we can boot it:
@@ -172,7 +160,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' 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: We can fetch information about any VM, as soon as it's created:
@@ -184,7 +172,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
-H 'Accept: application/json' -H 'Accept: application/json'
``` ```
##### Reboot a Virtual Machine #### Reboot a Virtual Machine
We can reboot a VM that's already booted: We can reboot a VM that's already booted:
@@ -194,7 +182,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' 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: Once booted, we can shut a VM down from the REST API:
@@ -204,50 +192,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' 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 ### Command Line Interface
The Cloud Hypervisor Command Line Interface (CLI) can only be used for launching The Cloud Hypervisor Command Line Interface (CLI) can only be used for launching
@@ -255,41 +199,33 @@ 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. the launched VM once they're up and running.
If you want to inspect the VMM, or control the VM after launching Cloud 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) Hypervisor from the CLI, you must use the [REST API](#rest-api).
or the [D-Bus API](#d-bus-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 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 the VM config. Run `cloud-hypervisor --help` for a complete list of CLI
options. As soon as the `cloud-hypervisor` binary is launched, contrary options. As soon as the `cloud-hypervisor` binary is launched, the
to the [D-Bus API](#d-bus-api), the [REST API](#rest-api) is available [REST API](#rest-api) is available for controlling and managing the VM.
for controlling and managing the VM. The [D-Bus API](#d-bus-api) doesn't start 1. Start the [REST API](#rest-api) server only, by not passing any VM
automatically and needs to be explicitly configured in order to be run. configuration options. The VM can then be asynchronously created and booted
1. Start either the REST API, D-Bus API or both simultaneously without passing by sending HTTP commands to the [REST API](#rest-api). Check the
any VM configuration options. The VM can then be asynchronously created and [REST API examples](#rest-api-examples) section for more details.
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.
### 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 The CLI options are parsed by the
[argh crate](https://docs.rs/argh/latest/argh/) and then translated into [argh crate](https://docs.rs/argh/latest/argh/) and then translated into
[internal API](#internal-api) commands. [internal API](#internal-api) commands.
The REST API is processed by an HTTP thread using the The REST API is processed by an HTTP thread using the
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/micro-http) [Firecracker's `micro_http`](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
crate. As with the CLI, the HTTP requests eventually get translated into crate. As with the CLI, the HTTP requests eventually get translated into
[internal API](#internal-api) commands. [internal API](#internal-api) commands.
The D-Bus API is implemented using the [zbus](https://github.com/dbus2/zbus) As a summary, the REST API and the CLI are essentially frontends for the
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
[internal API](#internal-api): [internal API](#internal-api):
``` ```
@@ -300,11 +236,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 | +----------+ | VMM
@@ -319,23 +255,22 @@ As a summary, the REST API, the D-Bus API and the CLI are essentially frontends
## Internal API ## Internal API
The Cloud Hypervisor internal API, as its name suggests, is used internally The Cloud Hypervisor internal API, as its name suggests, is used internally
by the different Cloud Hypervisor threads (VMM, HTTP, D-Bus, control loop, by the different Cloud Hypervisor threads (VMM, HTTP, control loop, etc) to
etc) to send commands and responses to each others. 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/), 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 and the single consumer (a.k.a. the API receiver) is the Cloud Hypervisor
control loop. control loop.
API producers are the HTTP thread handling the [REST API](#rest-api), the API producers are the HTTP thread handling the [REST API](#rest-api) and the
D-Bus thread handling the [D-Bus API](#d-bus-api) and the main thread that main thread that initially parses the [CLI](#command-line-interface).
initially parses the [CLI](#command-line-interface).
### Goals and Design ### Goals and Design
The internal API is designed for controlling, managing and inspecting a Cloud 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 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) visible requests through either the [REST API](#rest-api) or the
or the [CLI](#command-line-interface) interfaces. [CLI](#command-line-interface) interfaces.
The API follows a command-response scheme that closely maps the [REST API](#rest-api). The API follows a command-response scheme that closely maps the [REST API](#rest-api).
Any command must be replied to with a response. Any command must be replied to with a response.
@@ -444,5 +379,5 @@ APIs work together, let's look at a complete VM creation flow, from the
``` ```
1. The Cloud Hypervisor HTTP thread sends the formed HTTP response back to the 1. The Cloud Hypervisor HTTP thread sends the formed HTTP response back to the
user. This is abstracted by the user. This is abstracted by the
[micro_http](https://github.com/firecracker-microvm/micro-http) [micro_http](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
crate. crate.

View File

@@ -225,7 +225,7 @@ Number Start End Size File system Name Flags
### Create a macvtap interface ### 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. macvtap interface to provide your VM with proper connectivity.
### Boot the image ### Boot the image

View File

@@ -266,8 +266,11 @@ _Example_
### `file` ### `file`
Path to the file backing the memory zone. The file will be opened and used as Path to the file backing the memory zone. This can be either a file or a
the backing file for the `mmap(2)` operation. directory. In case of a file, it will be opened and used as the backing file
for the `mmap(2)` operation. In case of a directory, a temporary file with no
hard link on the filesystem will be created. This file will be used as the
backing file for the `mmap(2)` operation.
This option can be particularly useful when trying to back a part of the guest This option can be particularly useful when trying to back a part of the guest
RAM with a well known file. In the context of the snapshot/restore feature, and RAM with a well known file. In the context of the snapshot/restore feature, and

View File

@@ -6,5 +6,5 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.139" libc = "0.2.139"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"

230
fuzz/Cargo.lock generated
View File

@@ -5,16 +5,16 @@ version = 3
[[package]] [[package]]
name = "acpi_tables" name = "acpi_tables"
version = "0.1.0" 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#4fd38dd5f746730ec5ae848dafcf8c2f50a13fc3"
dependencies = [ dependencies = [
"zerocopy", "vm-memory",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.71" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -25,9 +25,9 @@ dependencies = [
[[package]] [[package]]
name = "arbitrary" name = "arbitrary"
version = "1.3.0" version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad"
[[package]] [[package]]
name = "arc-swap" name = "arc-swap"
@@ -76,7 +76,7 @@ dependencies = [
"argh_shared", "argh_shared",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn",
] ]
[[package]] [[package]]
@@ -100,12 +100,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
[[package]] [[package]]
name = "block_util" name = "block_util"
version = "0.1.0" version = "0.1.0"
@@ -119,7 +113,7 @@ dependencies = [
"versionize", "versionize",
"versionize_derive", "versionize_derive",
"vhdx", "vhdx",
"virtio-bindings", "virtio-bindings 0.2.0",
"virtio-queue", "virtio-queue",
"vm-memory", "vm-memory",
"vm-virtio", "vm-virtio",
@@ -149,7 +143,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "32.0.0" version = "29.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -214,9 +208,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.1" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"darling_macro", "darling_macro",
@@ -224,27 +218,27 @@ dependencies = [
[[package]] [[package]]
name = "darling_core" name = "darling_core"
version = "0.20.1" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.20.1" version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
@@ -254,7 +248,7 @@ dependencies = [
"acpi_tables", "acpi_tables",
"anyhow", "anyhow",
"arch", "arch",
"bitflags 2.3.2", "bitflags",
"byteorder", "byteorder",
"hypervisor", "hypervisor",
"libc", "libc",
@@ -275,7 +269,7 @@ version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0" checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
] ]
@@ -302,9 +296,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.10" version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@@ -332,9 +326,9 @@ dependencies = [
[[package]] [[package]]
name = "iced-x86" name = "iced-x86"
version = "1.19.0" version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5" checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
] ]
@@ -351,21 +345,21 @@ version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c" checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
] ]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.6" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.26" version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -399,9 +393,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -416,18 +410,21 @@ dependencies = [
[[package]] [[package]]
name = "linux-loader" name = "linux-loader"
version = "0.9.0" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d3adb7b28e189741eca3b1a4a27de0bf15e0907c9d4b0c74bd2d7d84ef72e08" checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
dependencies = [ dependencies = [
"vm-memory", "vm-memory",
] ]
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.19" version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "micro_http" name = "micro_http"
@@ -459,7 +456,7 @@ dependencies = [
"thiserror", "thiserror",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
"virtio-bindings", "virtio-bindings 0.2.0",
"virtio-queue", "virtio-queue",
"vm-memory", "vm-memory",
"vm-virtio", "vm-virtio",
@@ -468,9 +465,9 @@ dependencies = [
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.18.0" version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]] [[package]]
name = "option_parser" name = "option_parser"
@@ -501,9 +498,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.63" version = "1.0.51"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@@ -521,9 +518,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.28" version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -539,13 +536,13 @@ dependencies = [
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.8" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c" checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
@@ -559,9 +556,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.13" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]] [[package]]
name = "seccompiler" name = "seccompiler"
@@ -574,35 +571,35 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.17" version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.164" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.164" version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.99" version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -611,9 +608,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.0.0" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513" checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
dependencies = [ dependencies = [
"serde", "serde",
"serde_with_macros", "serde_with_macros",
@@ -621,14 +618,14 @@ dependencies = [
[[package]] [[package]]
name = "serde_with_macros" name = "serde_with_macros"
version = "3.0.0" version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070" checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
@@ -668,20 +665,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.109" version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -690,22 +676,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.40" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.40" version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn",
] ]
[[package]] [[package]]
@@ -734,24 +720,24 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.9" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.3.4" version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
[[package]] [[package]]
name = "versionize" name = "versionize"
version = "0.1.10" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f" checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
dependencies = [ dependencies = [
"bincode", "bincode",
"crc64", "crc64",
@@ -759,7 +745,7 @@ dependencies = [
"quote", "quote",
"serde", "serde",
"serde_derive", "serde_derive",
"syn 1.0.109", "syn",
"versionize_derive", "versionize_derive",
"vmm-sys-util", "vmm-sys-util",
] ]
@@ -767,17 +753,17 @@ dependencies = [
[[package]] [[package]]
name = "versionize_derive" name = "versionize_derive"
version = "0.1.4" version = "0.1.4"
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6" source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn",
] ]
[[package]] [[package]]
name = "vfio-bindings" name = "vfio-bindings"
version = "0.4.0" 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 = [ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
@@ -785,7 +771,7 @@ dependencies = [
[[package]] [[package]]
name = "vfio-ioctls" name = "vfio-ioctls"
version = "0.2.0" 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 = [ dependencies = [
"byteorder", "byteorder",
"kvm-bindings", "kvm-bindings",
@@ -801,9 +787,9 @@ dependencies = [
[[package]] [[package]]
name = "vfio_user" name = "vfio_user"
version = "0.1.0" 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 = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
"log", "log",
"serde", "serde",
@@ -830,16 +816,22 @@ dependencies = [
[[package]] [[package]]
name = "vhost" name = "vhost"
version = "0.7.0" version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f81f436bca4541f4d33172e1202882c9d437db34ed17fc6d84c8ff2bde21f5" checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
"vm-memory", "vm-memory",
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "virtio-bindings"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
[[package]] [[package]]
name = "virtio-bindings" name = "virtio-bindings"
version = "0.2.0" version = "0.2.0"
@@ -871,7 +863,7 @@ dependencies = [
"versionize", "versionize",
"versionize_derive", "versionize_derive",
"vhost", "vhost",
"virtio-bindings", "virtio-bindings 0.2.0",
"virtio-queue", "virtio-queue",
"vm-allocator", "vm-allocator",
"vm-device", "vm-device",
@@ -883,12 +875,12 @@ dependencies = [
[[package]] [[package]]
name = "virtio-queue" name = "virtio-queue"
version = "0.8.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91aebb1df33db33cbf04d4c2445e4f78d0b0c8e65acfd16a4ee95ef63ca252f8" checksum = "3ba81e2bcc21c0d2fc5e6683e79367e26ad219197423a498df801d79d5ba77bd"
dependencies = [ dependencies = [
"log", "log",
"virtio-bindings", "virtio-bindings 0.1.0",
"vm-memory", "vm-memory",
"vmm-sys-util", "vmm-sys-util",
] ]
@@ -922,9 +914,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
[[package]] [[package]]
name = "vm-memory" name = "vm-memory"
version = "0.11.0" version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6ea57fe00f9086c59eeeb68e102dd611686bc3c28520fa465996d4d4bdce07" checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
dependencies = [ dependencies = [
"arc-swap", "arc-swap",
"libc", "libc",
@@ -961,7 +953,7 @@ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
"arch", "arch",
"bitflags 2.3.2", "bitflags",
"block_util", "block_util",
"devices", "devices",
"epoll", "epoll",
@@ -997,7 +989,6 @@ dependencies = [
"vm-migration", "vm-migration",
"vm-virtio", "vm-virtio",
"vmm-sys-util", "vmm-sys-util",
"zerocopy",
] ]
[[package]] [[package]]
@@ -1006,7 +997,7 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
"serde", "serde",
"serde_derive", "serde_derive",
@@ -1039,24 +1030,3 @@ name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zerocopy"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
dependencies = [
"byteorder",
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]

View File

@@ -12,20 +12,20 @@ cargo-fuzz = true
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
devices = { path = "../devices" } devices = { path = "../devices" }
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.147" libc = "0.2.138"
libfuzzer-sys = "0.4.6" 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" } micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
net_util = { path = "../net_util" } net_util = { path = "../net_util" }
once_cell = "1.18.0" once_cell = "1.17.1"
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
seccompiler = "0.3.0" seccompiler = "0.3.0"
vhdx = { path = "../vhdx" } vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" } virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.8.0" virtio-queue = "0.7.1"
vmm = { path = "../vmm" } vmm = { path = "../vmm" }
vmm-sys-util = "0.11.1" vmm-sys-util = "0.11.1"
vm-memory = "0.11.0" vm-memory = "0.10.0"
vm-device = { path = "../vm-device" } vm-device = { path = "../vm-device" }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }

View File

@@ -6,28 +6,28 @@ edition = "2021"
license = "Apache-2.0 OR BSD-3-Clause" license = "Apache-2.0 OR BSD-3-Clause"
[features] [features]
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"] kvm = ["kvm-ioctls", "kvm-bindings"]
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"] mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = [] tdx = []
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
byteorder = "1.4.3" byteorder = "1.4.3"
thiserror = "1.0.40" thiserror = "1.0.38"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
kvm-ioctls = { version = "0.13.0", optional = true } 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 } 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-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} mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_with = { version = "3.0.0", default-features = false, features = ["macros"] } serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } 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"] } vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86] [target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
version = "1.19.0" version = "1.18.0"
default-features = false default-features = false
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"] features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]

View File

@@ -26,6 +26,7 @@ pub const MTRR_MEM_TYPE_WB: u64 = 0x6;
pub const NUM_IOAPIC_PINS: usize = 24; pub const NUM_IOAPIC_PINS: usize = 24;
// X86 Exceptions // X86 Exceptions
#[allow(clippy::upper_case_acronyms)]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Exception { pub enum Exception {
DE = 0, // Divide Error DE = 0, // Divide Error

View File

@@ -21,15 +21,6 @@ use crate::MpState;
use thiserror::Error; use thiserror::Error;
use vm_memory::GuestAddress; use vm_memory::GuestAddress;
#[cfg(target_arch = "x86_64")]
#[derive(Copy, Clone, Default)]
pub enum CpuVendor {
#[default]
Unknown,
Intel,
AMD,
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
/// ///
/// Enum for CPU error /// Enum for CPU error

View File

@@ -9,14 +9,10 @@
// //
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86::CpuIdEntry; use crate::arch::x86::CpuIdEntry;
#[cfg(target_arch = "x86_64")]
use crate::cpu::CpuVendor;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
use crate::kvm::TdxCapabilities; use crate::kvm::TdxCapabilities;
use crate::vm::Vm; use crate::vm::Vm;
use crate::HypervisorType; use crate::HypervisorType;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64;
use std::sync::Arc; use std::sync::Arc;
use thiserror::Error; use thiserror::Error;
@@ -79,11 +75,6 @@ pub enum HypervisorError {
/// ///
#[error("Failed to set partition property:{0}")] #[error("Failed to set partition property:{0}")]
SetPartitionProperty(#[source] anyhow::Error), SetPartitionProperty(#[source] anyhow::Error),
///
/// Running on an unsupported CPU
///
#[error("Unsupported CPU:{0}")]
UnsupportedCpu(#[source] anyhow::Error),
} }
/// ///
@@ -142,30 +133,4 @@ pub trait Hypervisor: Send + Sync {
fn get_guest_debug_hw_bps(&self) -> usize { fn get_guest_debug_hw_bps(&self) -> usize {
unimplemented!() unimplemented!()
} }
/// 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()
}
}
}
} }

View File

@@ -243,6 +243,7 @@ impl KvmGicV3Its {
} }
/// Method to initialize the GIC device /// Method to initialize the GIC device
#[allow(clippy::new_ret_no_self)]
pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> { pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
// This is inside KVM module // This is inside KVM module
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?"); let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");

View File

@@ -335,17 +335,16 @@ impl KvmVm {
} }
} }
///
/// Implementation of Vm trait for KVM /// Implementation of Vm trait for KVM
/// /// Example:
/// # Examples /// #[cfg(feature = "kvm")]
/// /// extern crate hypervisor
/// ``` /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// # use hypervisor::kvm::KvmHypervisor; /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ``` /// vm.set/get().unwrap()
///
impl vm::Vm for KvmVm { impl vm::Vm for KvmVm {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
@@ -918,16 +917,13 @@ impl KvmHypervisor {
} }
} }
/// Implementation of Hypervisor trait for KVM /// Implementation of Hypervisor trait for KVM
/// /// Example:
/// # Examples /// #[cfg(feature = "kvm")]
/// /// extern crate hypervisor
/// ``` /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// # use hypervisor::kvm::KvmHypervisor; /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ``` ///
impl hypervisor::Hypervisor for KvmHypervisor { impl hypervisor::Hypervisor for KvmHypervisor {
/// ///
/// Returns the type of the hypervisor /// Returns the type of the hypervisor
@@ -936,15 +932,13 @@ impl hypervisor::Hypervisor for KvmHypervisor {
HypervisorType::Kvm HypervisorType::Kvm
} }
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object /// Create a KVM vm object of a specific VM type and return the object as Vm trait object
/// /// Example
/// # Examples /// # extern crate hypervisor;
/// /// # use hypervisor::KvmHypervisor;
/// ``` /// use hypervisor::KvmVm;
/// # use hypervisor::kvm::KvmHypervisor;
/// use hypervisor::kvm::KvmVm;
/// let hypervisor = KvmHypervisor::new().unwrap(); /// let hypervisor = KvmHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm_with_type(0).unwrap(); /// let vm = hypervisor.create_vm_with_type(KvmVmType::LegacyVm).unwrap()
/// ``` ///
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn vm::Vm>> { fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn vm::Vm>> {
let fd: VmFd; let fd: VmFd;
loop { loop {
@@ -998,15 +992,13 @@ impl hypervisor::Hypervisor for KvmHypervisor {
} }
/// Create a KVM vm object and return the object as Vm trait object /// Create a KVM vm object and return the object as Vm trait object
/// /// Example
/// # Examples /// # extern crate hypervisor;
/// /// # use hypervisor::KvmHypervisor;
/// ``` /// use hypervisor::KvmVm;
/// # use hypervisor::kvm::KvmHypervisor;
/// use hypervisor::kvm::KvmVm;
/// let hypervisor = KvmHypervisor::new().unwrap(); /// let hypervisor = KvmHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm().unwrap(); /// let vm = hypervisor.create_vm().unwrap()
/// ``` ///
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut vm_type: u64 = 0; // Create with default platform type let mut vm_type: u64 = 0; // Create with default platform type
@@ -1084,11 +1076,6 @@ impl hypervisor::Hypervisor for KvmHypervisor {
self.kvm.get_guest_debug_hw_bps() as usize self.kvm.get_guest_debug_hw_bps() as usize
} }
} }
/// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32 {
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
}
} }
/// Vcpu struct for KVM /// Vcpu struct for KVM
pub struct KvmVcpu { pub struct KvmVcpu {
@@ -1100,17 +1087,15 @@ pub struct KvmVcpu {
hyperv_synic: AtomicBool, hyperv_synic: AtomicBool,
} }
/// Implementation of Vcpu trait for KVM /// Implementation of Vcpu trait for KVM
/// /// Example:
/// # Examples /// #[cfg(feature = "kvm")]
/// /// extern crate hypervisor
/// ``` /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// # use hypervisor::kvm::KvmHypervisor; /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap();
/// let hypervisor = Arc::new(kvm);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// let vcpu = vm.create_vcpu(0, None).unwrap(); /// let vcpu = vm.create_vcpu(0, None).unwrap();
/// ``` /// vcpu.get/set().unwrap()
///
impl cpu::Vcpu for KvmVcpu { impl cpu::Vcpu for KvmVcpu {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
@@ -1812,10 +1797,11 @@ impl cpu::Vcpu for KvmVcpu {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// # use hypervisor::kvm::KvmHypervisor; /// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// # use std::sync::Arc; /// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap(); /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hv = Arc::new(kvm); /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hv.create_vm().expect("new VM fd creation failed"); /// let vm = hv.create_vm().expect("new VM fd creation failed");
/// vm.enable_split_irq().unwrap(); /// vm.enable_split_irq().unwrap();
/// let vcpu = vm.create_vcpu(0, None).unwrap(); /// let vcpu = vm.create_vcpu(0, None).unwrap();
@@ -1983,10 +1969,11 @@ impl cpu::Vcpu for KvmVcpu {
/// # Example /// # Example
/// ///
/// ```rust /// ```rust
/// # use hypervisor::kvm::KvmHypervisor; /// # extern crate hypervisor;
/// # use hypervisor::KvmHypervisor;
/// # use std::sync::Arc; /// # use std::sync::Arc;
/// let kvm = KvmHypervisor::new().unwrap(); /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
/// let hv = Arc::new(kvm); /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
/// let vm = hv.create_vm().expect("new VM fd creation failed"); /// let vm = hv.create_vm().expect("new VM fd creation failed");
/// vm.enable_split_irq().unwrap(); /// vm.enable_split_irq().unwrap();
/// let vcpu = vm.create_vcpu(0, None).unwrap(); /// let vcpu = vm.create_vcpu(0, None).unwrap();

View File

@@ -48,11 +48,9 @@ mod cpu;
/// Device related module /// Device related module
mod device; 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 cpu::{HypervisorCpuError, Vcpu, VmExit};
pub use device::HypervisorDeviceError; pub use device::HypervisorDeviceError;
pub use hypervisor::{Hypervisor, HypervisorError};
#[cfg(all(feature = "kvm", target_arch = "aarch64"))] #[cfg(all(feature = "kvm", target_arch = "aarch64"))]
pub use kvm::{aarch64, GicState}; pub use kvm::{aarch64, GicState};
use std::sync::Arc; use std::sync::Arc;

View File

@@ -195,16 +195,13 @@ impl MshvHypervisor {
} }
} }
/// Implementation of Hypervisor trait for Mshv /// Implementation of Hypervisor trait for Mshv
/// /// Example:
/// # Examples /// #[cfg(feature = "mshv")]
/// /// extern crate hypervisor
/// ``` /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
/// # use hypervisor::mshv::MshvHypervisor; /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ``` ///
impl hypervisor::Hypervisor for MshvHypervisor { impl hypervisor::Hypervisor for MshvHypervisor {
/// ///
/// Returns the type of the hypervisor /// Returns the type of the hypervisor
@@ -213,16 +210,13 @@ impl hypervisor::Hypervisor for MshvHypervisor {
HypervisorType::Mshv HypervisorType::Mshv
} }
/// Create a mshv vm object and return the object as Vm trait object /// Create a mshv vm object and return the object as Vm trait object
/// /// Example
/// # Examples
///
/// ```
/// # extern crate hypervisor; /// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor; /// # use hypervisor::MshvHypervisor;
/// use hypervisor::mshv::MshvVm; /// use hypervisor::MshvVm;
/// let hypervisor = MshvHypervisor::new().unwrap(); /// let hypervisor = MshvHypervisor::new().unwrap();
/// let vm = hypervisor.create_vm().unwrap(); /// let vm = hypervisor.create_vm().unwrap()
/// ``` ///
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
let fd: VmFd; let fd: VmFd;
loop { loop {
@@ -279,13 +273,6 @@ impl hypervisor::Hypervisor for MshvHypervisor {
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> { fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
Ok(Vec::new()) Ok(Vec::new())
} }
/// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32 {
// TODO: Using HV_MAXIMUM_PROCESSORS would be better
// but the ioctl API is limited to u8
256
}
} }
/// Vcpu struct for Microsoft Hypervisor /// Vcpu struct for Microsoft Hypervisor
@@ -298,17 +285,15 @@ pub struct MshvVcpu {
} }
/// Implementation of Vcpu trait for Microsoft Hypervisor /// Implementation of Vcpu trait for Microsoft Hypervisor
/// /// Example:
/// # Examples /// #[cfg(feature = "mshv")]
/// /// extern crate hypervisor
/// ``` /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
/// # use hypervisor::mshv::MshvHypervisor; /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// let vcpu = vm.create_vcpu(0, None).unwrap(); /// let vcpu = vm.create_vcpu(0).unwrap();
/// ``` /// vcpu.get/set().unwrap()
///
impl cpu::Vcpu for MshvVcpu { impl cpu::Vcpu for MshvVcpu {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
@@ -461,10 +446,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */ /* Advance RIP and update RAX */
let arr_reg_name_value = [ 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, 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) set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -510,10 +495,10 @@ impl cpu::Vcpu for MshvVcpu {
/* Advance RIP and update RAX */ /* Advance RIP and update RAX */
let arr_reg_name_value = [ 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, 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) set_registers_64!(self.fd, arr_reg_name_value)
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?; .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
@@ -583,14 +568,8 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// X86 specific call to setup the CPUID registers. /// X86 specific call to setup the CPUID registers.
/// ///
fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> { fn set_cpuid2(&self, _cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect(); Ok(())
let mshv_cpuid = <CpuId>::from_entries(&cpuid)
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
self.fd
.register_intercept_result_cpuid(&mshv_cpuid)
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
} }
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///
@@ -938,17 +917,15 @@ impl MshvVm {
/// ///
/// Implementation of Vm trait for Mshv /// Implementation of Vm trait for Mshv
/// /// Example:
/// # Examples /// #[cfg(feature = "mshv")]
///
/// ```
/// # extern crate hypervisor; /// # extern crate hypervisor;
/// # use hypervisor::mshv::MshvHypervisor; /// # use hypervisor::MshvHypervisor;
/// # use std::sync::Arc;
/// let mshv = MshvHypervisor::new().unwrap(); /// let mshv = MshvHypervisor::new().unwrap();
/// let hypervisor = Arc::new(mshv); /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
/// ``` /// vm.set/get().unwrap()
///
impl vm::Vm for MshvVm { impl vm::Vm for MshvVm {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
/// ///

View File

@@ -10,7 +10,6 @@
#[repr(C)] #[repr(C)]
#[derive(Default)] #[derive(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]); pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
#[allow(clippy::missing_safety_doc)]
impl<T> __IncompleteArrayField<T> { impl<T> __IncompleteArrayField<T> {
#[inline] #[inline]
pub const fn new() -> Self { pub const fn new() -> Self {

View File

@@ -10,7 +10,6 @@
#[repr(C)] #[repr(C)]
#[derive(Default)] #[derive(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]); pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
#[allow(clippy::missing_safety_doc)]
impl<T> __IncompleteArrayField<T> { impl<T> __IncompleteArrayField<T> {
#[inline] #[inline]
pub const fn new() -> Self { pub const fn new() -> Self {

View File

@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file. // found in the THIRD-PARTY file.
#![allow(clippy::all)]
#![allow(non_upper_case_globals)] #![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(non_snake_case)] #![allow(non_snake_case)]
@@ -27,12 +28,10 @@ pub mod inn;
// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust // generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
// --constified-enum '*' --with-derive-default // --constified-enum '*' --with-derive-default
pub mod sockios; pub mod sockios;
pub use if_tun::{ pub use if_tun::*;
sock_fprog, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TAP, IFF_VNET_HDR, TUN_F_CSUM, TUN_F_TSO4, pub use iff::*;
TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO, pub use inn::*;
}; pub use sockios::*;
pub use iff::{ifreq, net_device_flags_IFF_UP, setsockopt, sockaddr, AF_INET};
pub use inn::sockaddr_in;
pub const TUNTAP: ::std::os::raw::c_uint = 84; pub const TUNTAP: ::std::os::raw::c_uint = 84;

View File

@@ -11,13 +11,13 @@ libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
serde = "1.0.164" serde = "1.0.151"
thiserror = "1.0.40" thiserror = "1.0.38"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
virtio-bindings = "0.2.0" virtio-bindings = "0.2.0"
virtio-queue = "0.8.0" virtio-queue = "0.7.0"
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-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"
@@ -25,4 +25,4 @@ vmm-sys-util = "0.11.0"
once_cell = "1.17.1" once_cell = "1.17.1"
pnet = "0.33.0" pnet = "0.33.0"
pnet_datalink = "0.33.0" pnet_datalink = "0.33.0"
serde_json = "1.0.96" serde_json = "1.0.93"

View File

@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
byteorder = "1.4.3" byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] } 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" vmm-sys-util = "0.11.0"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
serde = { version = "1.0.164", features = ["derive"] } serde = { version = "1.0.151", features = ["derive"] }
thiserror = "1.0.40" thiserror = "1.0.38"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } 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-migration = { path = "../vm-migration" }

View File

@@ -452,9 +452,10 @@ impl From<PciBarType> for PciBarRegionType {
} }
} }
impl From<PciBarRegionType> for PciBarType { #[allow(clippy::from_over_into)]
fn from(val: PciBarRegionType) -> Self { impl Into<PciBarType> for PciBarRegionType {
match val { fn into(self) -> PciBarType {
match self {
PciBarRegionType::IoRegion => PciBarType::Io, PciBarRegionType::IoRegion => PciBarType::Io,
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32, PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64, PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
@@ -468,9 +469,10 @@ pub enum PciBarPrefetchable {
Prefetchable = 0x08, Prefetchable = 0x08,
} }
impl From<PciBarPrefetchable> for bool { #[allow(clippy::from_over_into)]
fn from(val: PciBarPrefetchable) -> Self { impl Into<bool> for PciBarPrefetchable {
match val { fn into(self) -> bool {
match self {
PciBarPrefetchable::NotPrefetchable => false, PciBarPrefetchable::NotPrefetchable => false,
PciBarPrefetchable::Prefetchable => true, PciBarPrefetchable::Prefetchable => true,
} }

View File

@@ -511,16 +511,6 @@ impl MsixCap {
self.pba & 0xffff_fff8 self.pba & 0xffff_fff8
} }
pub fn table_set_offset(&mut self, addr: u32) {
self.table &= 0x7;
self.table += addr;
}
pub fn pba_set_offset(&mut self, addr: u32) {
self.pba &= 0x7;
self.pba += addr;
}
pub fn table_bir(&self) -> u32 { pub fn table_bir(&self) -> u32 {
self.table & 0x7 self.table & 0x7
} }

View File

@@ -14,7 +14,6 @@ use crate::{
use anyhow::anyhow; use anyhow::anyhow;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use hypervisor::HypervisorVmError; use hypervisor::HypervisorVmError;
use libc::{sysconf, _SC_PAGESIZE};
use std::any::Any; use std::any::Any;
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::io; use std::io;
@@ -28,9 +27,6 @@ use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::{ use vfio_ioctls::{
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea, VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
}; };
use vm_allocator::page_size::{
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
};
use vm_allocator::{AddressAllocator, SystemAllocator}; use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::interrupt::{ use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig, InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
@@ -502,29 +498,6 @@ impl VfioCommon {
Ok(vfio_common) Ok(vfio_common)
} }
/// In case msix table offset is not page size aligned, we need do some fixup to achive it.
/// Becuse we don't want the MMIO RW region and trap region overlap each other.
fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
let msix = self.interrupt.msix.as_mut().unwrap();
let msix_cap = &mut msix.cap;
// Suppose table_bir equals to pba_bir here. Am I right?
let (table_offset, table_size) = msix_cap.table_range();
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
return region_size;
}
let (pba_offset, pba_size) = msix_cap.pba_range();
let msix_sz = align_page_size_up(table_size + pba_size);
// Expand region to hold RW and trap region which both page size aligned
let size = std::cmp::max(region_size * 2, msix_sz * 2);
// let table starts from the middle of the region
msix_cap.table_set_offset((size / 2) as u32);
msix_cap.pba_set_offset((size / 2 + pba_offset - table_offset) as u32);
size
}
pub(crate) fn allocate_bars( pub(crate) fn allocate_bars(
&mut self, &mut self,
allocator: &Arc<Mutex<SystemAllocator>>, allocator: &Arc<Mutex<SystemAllocator>>,
@@ -688,16 +661,9 @@ impl VfioCommon {
.ok_or(PciDeviceError::IoAllocationFailed(region_size))? .ok_or(PciDeviceError::IoAllocationFailed(region_size))?
} }
PciBarRegionType::Memory64BitRegion => { PciBarRegionType::Memory64BitRegion => {
// We need do some fixup to keep MMIO RW region and msix cap region page size // BAR allocation must be naturally aligned
// aligned.
region_size = self.fixup_msix_region(bar_id, region_size);
mmio_allocator mmio_allocator
.allocate( .allocate(restored_bar_addr, region_size, Some(region_size))
restored_bar_addr,
region_size,
// SAFETY: FFI call. Trivially safe.
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
)
.ok_or(PciDeviceError::IoAllocationFailed(region_size))? .ok_or(PciDeviceError::IoAllocationFailed(region_size))?
} }
}; };
@@ -834,23 +800,6 @@ impl VfioCommon {
}); });
} }
pub(crate) fn get_msix_cap_idx(&self) -> Option<usize> {
let mut cap_next = self
.vfio_wrapper
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
while cap_next != 0 {
let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX {
return Some(cap_next as usize);
} else {
cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
}
}
None
}
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) { pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
let mut cap_next = self let mut cap_next = self
.vfio_wrapper .vfio_wrapper
@@ -1205,15 +1154,6 @@ impl VfioCommon {
return self.configuration.read_reg(reg_idx); return self.configuration.read_reg(reg_idx);
} }
if let Some(id) = self.get_msix_cap_idx() {
let msix = self.interrupt.msix.as_mut().unwrap();
if reg_idx * 4 == id + 4 {
return msix.cap.table;
} else if reg_idx * 4 == id + 8 {
return msix.cap.pba;
}
}
// Since we don't support passing multi-functions devices, we should // Since we don't support passing multi-functions devices, we should
// mask the multi-function bit, bit 7 of the Header Type byte on the // mask the multi-function bit, bit 7 of the Header Type byte on the
// register 3. // register 3.
@@ -1376,6 +1316,18 @@ impl VfioPciDevice {
self.iommu_attached self.iommu_attached
} }
fn align_4k(address: u64) -> u64 {
(address + 0xfff) & 0xffff_ffff_ffff_f000
}
fn is_4k_aligned(address: u64) -> bool {
(address & 0xfff) == 0
}
fn is_4k_multiple(size: u64) -> bool {
(size & 0xfff) == 0
}
fn generate_sparse_areas( fn generate_sparse_areas(
caps: &[VfioRegionInfoCap], caps: &[VfioRegionInfoCap],
region_index: u32, region_index: u32,
@@ -1387,14 +1339,14 @@ impl VfioPciDevice {
match cap { match cap {
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()), VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
VfioRegionInfoCap::MsixMappable => { VfioRegionInfoCap::MsixMappable => {
if !is_4k_aligned(region_start) { if !Self::is_4k_aligned(region_start) {
error!( error!(
"Region start address 0x{:x} must be at least aligned on 4KiB", "Region start address 0x{:x} must be at least aligned on 4KiB",
region_start region_start
); );
return Err(VfioPciError::RegionAlignment); return Err(VfioPciError::RegionAlignment);
} }
if !is_4k_multiple(region_size) { if !Self::is_4k_multiple(region_size) {
error!( error!(
"Region size 0x{:x} must be at least a multiple of 4KiB", "Region size 0x{:x} must be at least a multiple of 4KiB",
region_size region_size
@@ -1406,8 +1358,7 @@ impl VfioPciDevice {
// the MSI-X PBA table, we must calculate the subregions // the MSI-X PBA table, we must calculate the subregions
// around them, leading to a list of sparse areas. // around them, leading to a list of sparse areas.
// We want to make sure we will still trap MMIO accesses // We want to make sure we will still trap MMIO accesses
// to these MSI-X specific ranges. If these region don't align // to these MSI-X specific ranges.
// with pagesize, we can achive it by enlarging its range.
// //
// Using a BtreeMap as the list provided through the iterator is sorted // Using a BtreeMap as the list provided through the iterator is sorted
// by key. This ensures proper split of the whole region. // by key. This ensures proper split of the whole region.
@@ -1415,14 +1366,10 @@ impl VfioPciDevice {
if let Some(msix) = vfio_msix { if let Some(msix) = vfio_msix {
if region_index == msix.cap.table_bir() { if region_index == msix.cap.table_bir() {
let (offset, size) = msix.cap.table_range(); let (offset, size) = msix.cap.table_range();
let offset = align_page_size_down(offset);
let size = align_page_size_up(size);
inter_ranges.insert(offset, size); inter_ranges.insert(offset, size);
} }
if region_index == msix.cap.pba_bir() { if region_index == msix.cap.pba_bir() {
let (offset, size) = msix.cap.pba_range(); let (offset, size) = msix.cap.pba_range();
let offset = align_page_size_down(offset);
let size = align_page_size_up(size);
inter_ranges.insert(offset, size); inter_ranges.insert(offset, size);
} }
} }
@@ -1436,7 +1383,8 @@ impl VfioPciDevice {
size: range_offset - current_offset, size: range_offset - current_offset,
}); });
} }
current_offset = align_page_size_down(range_offset + range_size);
current_offset = Self::align_4k(range_offset + range_size);
} }
if region_size > current_offset { if region_size > current_offset {
@@ -1534,15 +1482,6 @@ impl VfioPciDevice {
return Err(VfioPciError::MmapArea); return Err(VfioPciError::MmapArea);
} }
if !is_page_size_aligned(area.size) || !is_page_size_aligned(area.offset) {
warn!(
"Could not mmap sparse area that is not page size aligned (offset = 0x{:x}, size = 0x{:x})",
area.offset,
area.size,
);
return Ok(());
}
let user_memory_region = UserMemoryRegion { let user_memory_region = UserMemoryRegion {
slot: (self.memory_slot)(), slot: (self.memory_slot)(),
start: region.start.0 + area.offset, start: region.start.0 + area.offset,

View File

@@ -7,9 +7,9 @@ build = "../build.rs"
[dependencies] [dependencies]
argh = "0.1.9" argh = "0.1.9"
dirs = "5.0.0" dirs = "4.0.0"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"
test_infra = { path = "../test_infra" } test_infra = { path = "../test_infra" }
thiserror = "1.0.40" thiserror = "1.0.38"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -110,23 +110,18 @@ impl Default for MetricsReport {
#[derive(Default)] #[derive(Default)]
pub struct PerformanceTestOverrides { pub struct PerformanceTestOverrides {
test_iterations: Option<u32>, test_iterations: Option<u32>,
test_timeout: Option<u32>,
} }
impl fmt::Display for PerformanceTestOverrides { impl fmt::Display for PerformanceTestOverrides {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(test_iterations) = self.test_iterations { if let Some(test_iterations) = self.test_iterations {
write!(f, "test_iterations = {test_iterations}, ")?; write!(f, "test_iterations = {test_iterations}")?;
}
if let Some(test_timeout) = self.test_timeout {
write!(f, "test_timeout = {test_timeout}")?;
} }
Ok(()) Ok(())
} }
} }
#[derive(Clone)]
pub struct PerformanceTestControl { pub struct PerformanceTestControl {
test_timeout: u32, test_timeout: u32,
test_iterations: u32, test_iterations: u32,
@@ -193,14 +188,7 @@ impl PerformanceTest {
.test_iterations .test_iterations
.unwrap_or(self.control.test_iterations) .unwrap_or(self.control.test_iterations)
{ {
// update the timeout in control if passed explicitly and run testcase with it metrics.push((self.func_ptr)(&self.control));
if let Some(test_timeout) = overrides.test_timeout {
let mut control: PerformanceTestControl = self.control.clone();
control.test_timeout = test_timeout;
metrics.push((self.func_ptr)(&control));
} else {
metrics.push((self.func_ptr)(&self.control));
}
} }
let mean = (self.unit_adjuster)(mean(&metrics).unwrap()); let mean = (self.unit_adjuster)(mean(&metrics).unwrap());
@@ -219,9 +207,9 @@ impl PerformanceTest {
// Calculate the timeout for each test // Calculate the timeout for each test
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test // Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
pub fn calc_timeout(&self, test_iterations: &Option<u32>, test_timeout: &Option<u32>) -> u64 { pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 {
((test_timeout.unwrap_or(self.control.test_timeout) + 20) ((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations))
* test_iterations.unwrap_or(self.control.test_iterations)) as u64 as u64
} }
} }
@@ -599,7 +587,6 @@ fn run_test_with_timeout(
) -> Result<PerformanceTestResult, Error> { ) -> Result<PerformanceTestResult, Error> {
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>(); let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
let test_iterations = overrides.test_iterations; let test_iterations = overrides.test_iterations;
let test_timeout = overrides.test_timeout;
let overrides = overrides.clone(); let overrides = overrides.clone();
thread::spawn(move || { thread::spawn(move || {
println!( println!(
@@ -622,7 +609,7 @@ fn run_test_with_timeout(
}); });
// Todo: Need to cleanup/kill all hanging child processes // Todo: Need to cleanup/kill all hanging child processes
let test_timeout = test.calc_timeout(&test_iterations, &test_timeout); let test_timeout = test.calc_timeout(&test_iterations);
receiver receiver
.recv_timeout(Duration::from_secs(test_timeout)) .recv_timeout(Duration::from_secs(test_timeout))
.map_err(|_| { .map_err(|_| {
@@ -658,10 +645,6 @@ struct Options {
/// override number of test iterations /// override number of test iterations
iterations: Option<u32>, iterations: Option<u32>,
#[argh(option, long = "timeout")]
/// override test timeout, Ex. --timeout 5
timeout: Option<u32>,
#[argh(switch, short = 'V', long = "version")] #[argh(switch, short = 'V', long = "version")]
/// print version information /// print version information
version: bool, version: bool,
@@ -671,7 +654,7 @@ fn main() {
let opts: Options = argh::from_env(); let opts: Options = argh::from_env();
if opts.version { if opts.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return; return;
} }
@@ -700,7 +683,6 @@ fn main() {
let overrides = Arc::new(PerformanceTestOverrides { let overrides = Arc::new(PerformanceTestOverrides {
test_iterations: opts.iterations, test_iterations: opts.iterations,
test_timeout: opts.timeout,
}); });
for test in test_list.iter() { for test in test_list.iter() {

View File

@@ -66,7 +66,7 @@ impl QcowRawFile {
non_zero_flags: u64, non_zero_flags: u64,
) -> io::Result<()> { ) -> io::Result<()> {
self.file.seek(SeekFrom::Start(offset))?; self.file.seek(SeekFrom::Start(offset))?;
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file); let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &mut self.file);
for addr in table { for addr in table {
let val = if *addr == 0 { let val = if *addr == 0 {
0 0
@@ -91,8 +91,7 @@ impl QcowRawFile {
/// Writes a refcount block to the file. /// Writes a refcount block to the file.
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> { pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
self.file.seek(SeekFrom::Start(offset))?; self.file.seek(SeekFrom::Start(offset))?;
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file); let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &mut self.file);
for count in table { for count in table {
buffer.write_u16::<BigEndian>(*count)?; buffer.write_u16::<BigEndian>(*count)?;
} }

View File

@@ -1,29 +1,11 @@
- [v33.0](#v330) - [v30.1](#v301)
- [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.1](#v311)
- [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
- [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)
- [v30.0](#v300) - [v30.0](#v300)
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size) - [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
- [Basic vfio-user Server Support](#basic-vfio-user-server-support) - [Basic vfio-user Server Support](#basic-vfio-user-server-support)
- [Heap Profiling Support](#heap-profiling-support) - [Heap Profiling Support](#heap-profiling-support)
- [Documentation Improvements](#documentation-improvements-1) - [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-3) - [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors-3) - [Contributors](#contributors)
- [v28.2](#v282) - [v28.2](#v282)
- [v29.0](#v290) - [v29.0](#v290)
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm) - [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
@@ -33,10 +15,10 @@
- [`AArch64` Documentation Integration](#aarch64-documentation-integration) - [`AArch64` Documentation Integration](#aarch64-documentation-integration)
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement) - [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
- [TCP Offload Control](#tcp-offload-control) - [TCP Offload Control](#tcp-offload-control)
- [Notable Bug Fixes](#notable-bug-fixes-4) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Removals](#removals) - [Removals](#removals)
- [Deprecations](#deprecations) - [Deprecations](#deprecations)
- [Contributors](#contributors-4) - [Contributors](#contributors-1)
- [v28.1](#v281) - [v28.1](#v281)
- [v28.0](#v280) - [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder) - [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -44,9 +26,9 @@
- [Virtualised TPM Support](#virtualised-tpm-support) - [Virtualised TPM Support](#virtualised-tpm-support)
- [Transparent Huge Page Support](#transparent-huge-page-support) - [Transparent Huge Page Support](#transparent-huge-page-support)
- [README Quick Start Improved](#readme-quick-start-improved) - [README Quick Start Improved](#readme-quick-start-improved)
- [Notable Bug Fixes](#notable-bug-fixes-5) - [Notable Bug Fixes](#notable-bug-fixes-2)
- [Removals](#removals-1) - [Removals](#removals-1)
- [Contributors](#contributors-5) - [Contributors](#contributors-2)
- [v27.0](#v270) - [v27.0](#v270)
- [Community Engagement](#community-engagement) - [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages) - [Prebuilt Packages](#prebuilt-packages)
@@ -55,41 +37,41 @@
- [Simplified Build Feature Flags](#simplified-build-feature-flags) - [Simplified Build Feature Flags](#simplified-build-feature-flags)
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading) - [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
- [GDB Support for AArch64](#gdb-support-for-aarch64) - [GDB Support for AArch64](#gdb-support-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-6) - [Notable Bug Fixes](#notable-bug-fixes-3)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-6) - [Contributors](#contributors-3)
- [v26.0](#v260) - [v26.0](#v260)
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform) - [SMBIOS Improvements via `--platform`](#smbios-improvements-via-platform)
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support) - [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-4)
- [Deprecations](#deprecations-2) - [Deprecations](#deprecations-2)
- [Removals](#removals-2) - [Removals](#removals-2)
- [Contributors](#contributors-7) - [Contributors](#contributors-4)
- [v25.0](#v250) - [v25.0](#v250)
- [`ch-remote` Improvements](#ch-remote-improvements-1) - [`ch-remote` Improvements](#ch-remote-improvements-1)
- [VM "Coredump" Support](#vm-coredump-support) - [VM "Coredump" Support](#vm-coredump-support)
- [Notable Bug Fixes](#notable-bug-fixes-8) - [Notable Bug Fixes](#notable-bug-fixes-5)
- [Removals](#removals-3) - [Removals](#removals-3)
- [Contributors](#contributors-8) - [Contributors](#contributors-5)
- [v24.0](#v240) - [v24.0](#v240)
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu) - [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness) - [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
- [Sparse Mmap support](#sparse-mmap-support) - [Sparse Mmap support](#sparse-mmap-support)
- [Expose Platform Serial Number](#expose-platform-serial-number) - [Expose Platform Serial Number](#expose-platform-serial-number)
- [Notable Bug Fixes](#notable-bug-fixes-9) - [Notable Bug Fixes](#notable-bug-fixes-6)
- [Notable Improvements](#notable-improvements) - [Notable Improvements](#notable-improvements)
- [Deprecations](#deprecations-3) - [Deprecations](#deprecations-3)
- [New on the Website](#new-on-the-website) - [New on the Website](#new-on-the-website)
- [Contributors](#contributors-9) - [Contributors](#contributors-6)
- [v23.1](#v231) - [v23.1](#v231)
- [v23.0](#v230) - [v23.0](#v230)
- [vDPA Support](#vdpa-support) - [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list) - [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements) - [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support) - [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes-10) - [Notable Bug Fixes](#notable-bug-fixes-7)
- [Deprecations](#deprecations-4) - [Deprecations](#deprecations-4)
- [Contributors](#contributors-10) - [Contributors](#contributors-7)
- [v22.1](#v221) - [v22.1](#v221)
- [v22.0](#v220) - [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support) - [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -100,13 +82,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64) - [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license) - [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd) - [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-11) - [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-11) - [Contributors](#contributors-8)
- [v21.0](#v210) - [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade) - [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) - [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-12) - [Notable Bug fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-12) - [Contributors](#contributors-9)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -115,8 +97,8 @@
- [Improved VFIO support](#improved-vfio-support) - [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code) - [Safer code](#safer-code)
- [Extended documentation](#extended-documentation) - [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-13) - [Notable bug fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-13) - [Contributors](#contributors-10)
- [v19.0](#v190) - [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console) - [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations) - [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -124,8 +106,8 @@
- [Live migration enhancements](#live-migration-enhancements) - [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user) - [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu) - [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-14) - [Notable bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-14) - [Contributors](#contributors-11)
- [v18.0](#v180) - [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support) - [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices) - [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -135,31 +117,31 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor) - [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support) - [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64) - [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-15) - [Notable bug fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-15) - [Contributors](#contributors-12)
- [v17.0](#v170) - [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi) - [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend) - [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices) - [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support) - [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices) - [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-16) - [Notable bug fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-16) - [Contributors](#contributors-13)
- [v16.0](#v160) - [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support) - [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support) - [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support) - [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-17) - [Notable bug fixes](#notable-bug-fixes-14)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-17) - [Contributors](#contributors-14)
- [v15.0](#v150) - [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees) - [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting) - [Network device rate limiting](#network-device-rate-limiting)
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload) - [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter) - [`--api-socket` supports file descriptor parameter](#-api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes) - [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-5) - [Deprecations](#deprecations-5)
- [Contributors](#contributors-18) - [Contributors](#contributors-15)
- [v0.14.1](#v0141) - [v0.14.1](#v0141)
- [v0.14.0](#v0140) - [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring) - [Structured event monitoring](#structured-event-monitoring)
@@ -169,7 +151,7 @@
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console) - [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting) - [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-6) - [Deprecations](#deprecations-6)
- [Contributors](#contributors-19) - [Contributors](#contributors-16)
- [v0.13.0](#v0130) - [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support) - [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support) - [Improved huge page support](#improved-huge-page-support)
@@ -177,13 +159,13 @@
- [VHD disk image support](#vhd-disk-image-support) - [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading) - [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button) - [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-20) - [Contributors](#contributors-17)
- [v0.12.0](#v0120) - [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements) - [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) - [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) - [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api) - [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-21) - [Contributors](#contributors-18)
- [v0.11.0](#v0110) - [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block) - [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support) - [Windows Guest Support](#windows-guest-support)
@@ -193,17 +175,17 @@
- [Improved Linux Boot Time](#improved-linux-boot-time) - [Improved Linux Boot Time](#improved-linux-boot-time)
- [`SIGTERM/SIGINT` Interrupt Signal Handling](#sigtermsigint-interrupt-signal-handling) - [`SIGTERM/SIGINT` Interrupt Signal Handling](#sigtermsigint-interrupt-signal-handling)
- [Default Log Level Changed](#default-log-level-changed) - [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added) - [New `--balloon` Parameter Added](#new-balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support) - [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-18) - [Notable Bug Fixes](#notable-bug-fixes-15)
- [Contributors](#contributors-22) - [Contributors](#contributors-19)
- [v0.10.0](#v0100) - [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors) - [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones) - [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control) - [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-19) - [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-23) - [Contributors](#contributors-20)
- [v0.9.0](#v090) - [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support) - [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics) - [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -216,17 +198,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support) - [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support) - [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1) - [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-20) - [Notable Bug Fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-24) - [Contributors](#contributors-21)
- [v0.8.0](#v080) - [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support) - [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support) - [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests) - [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) - [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements) - [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-21) - [Notable Bug Fixes](#notable-bug-fixes-18)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-25) - [Contributors](#contributors-22)
- [v0.7.0](#v070) - [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug) - [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support) - [Alternative `libc` Support](#alternative-libc-support)
@@ -236,14 +218,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing) - [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support) - [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1) - [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-26) - [Contributors](#contributors-23)
- [v0.6.0](#v060) - [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug) - [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements) - [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading) - [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface) - [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot) - [PVH Boot](#pvh-boot)
- [Contributors](#contributors-27) - [Contributors](#contributors-24)
- [v0.5.1](#v051) - [v0.5.1](#v051)
- [v0.5.0](#v050) - [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing) - [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -251,7 +233,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework) - [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools) - [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration) - [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-28) - [Contributors](#contributors-25)
- [v0.4.0](#v040) - [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition) - [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation) - [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -260,7 +242,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default) - [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming) - [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization) - [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-29) - [Contributors](#contributors-26)
- [v0.3.0](#v030) - [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading) - [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend) - [Network device backend](#network-device-backend)
@@ -287,94 +269,7 @@
- [Unit testing](#unit-testing) - [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization) - [Integration tests parallelization](#integration-tests-parallelization)
# v33.0 # v30.1
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
* 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)
* 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: This is a bug fix release. The following issues have been addressed:
@@ -383,72 +278,10 @@ This is a bug fix release. The following issues have been addressed:
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360) * Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
* Only touch the tty flags if it's being used (#5343) * Only touch the tty flags if it's being used (#5343)
* Fix seccomp filter lists for vhost-user devices (#5361) * Fix seccomp filter lists for vhost-user devices (#5361)
* Fix the offset setting while removing the entire mapping of
# v31.0 `vhost-user` FS client (#5235)
* Fix the `ShutdownVmm` and `Shutdown` commands to call the correct API
This release has been tracked in our [roadmap endpoint (#5322)
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v31.0. The following user visible changes have been made:
### Update to Latest `acpi_tables`
Adapted to the latest [acpi_tables](https://github.com/rust-vmm/acpi_tables).
There has been significant API changes in the crate.
### Update Reference Kernel to 6.2
Updated the recommended guest kernel version from 6.1.6 to 6.2.
### Improvements on Console `SIGWINCH` Handler
A separate thread had been created to capture the `SIGWINCH` signal and resize
the guest console. Now the thread is skipped if the console is not resizable.
Two completely different code paths existed for handling console resizing, one
for `tty` and the other for `pty`. That makes the understanding of the console
handling code unnecessarily complicated. Now the code paths are unified. Both
`tty` and `pty` are supported in single `SIGWINCH` handler. And the new handler
can works with kernel versions earlier than v5.5.
### Remove Directory Support from `MemoryZoneConfig::file`
Setting a directory to `MemoryZoneConfig::file` is no longer supported.
Before this change, user can set a directory to `file` of the `--memory-zone`
option. In that case, a temporary file will be created as the backing file for
the `mmap(2)` operation. This functionality has been unnecessary since we had
the native support for hugepages and allocating anonymous shared memory.
### Documentation Improvements
* Various improvements in API document
* Improvements in Doc comments
* Updated Slack channel information in README
### Notable Bug Fixes
* Fixed the offset setting while removing the entire mapping of `vhost-user` FS
client.
* Fixed the `ShutdownVmm` and `Shutdown` commands to call the correct API
endpoint.
### Contributors
Many thanks to everyone who has contributed to our release:
* Alyssa Ross <hi@alyssa.is>
* Bo Chen <chen.bo@intel.com>
* Daniel Farina <daniel@fdr.io>
* Dom <peng6662001@163.com>
* Hao Xu <howeyxu@tencent.com>
* Muminul Islam <muislam@microsoft.com>
* Omer Faruk Bayram <omer.faruk@sartura.hr>
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Smit Gardhariya <gardhariya.smit@gmail.com>
* Yang <ailin.yang@intel.com>
* Yong He <alexyonghe@tencent.com>
# v30.0 # v30.0

View File

@@ -1,12 +1,10 @@
# SPDX-License-Identifier: Apache-2.0
#
# When changing this file don't forget to update the tag name in the # When changing this file don't forget to update the tag name in the
# .github/workflows/docker-image.yaml file if doing multiple per day # .github/workflows/docker-image.yaml file if doing multiple per day
FROM ubuntu:20.04 as dev FROM ubuntu:20.04 as dev
ARG TARGETARCH ARG TARGETARCH
ARG RUST_TOOLCHAIN="1.67.1" ARG RUST_TOOLCHAIN="1.66.1"
ARG CLH_SRC_DIR="/cloud-hypervisor" ARG CLH_SRC_DIR="/cloud-hypervisor"
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build" ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry" ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
@@ -15,67 +13,58 @@ ARG CARGO_GIT_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_git_registry"
ENV CARGO_HOME=/usr/local/rust ENV CARGO_HOME=/usr/local/rust
ENV RUSTUP_HOME=$CARGO_HOME ENV RUSTUP_HOME=$CARGO_HOME
ENV PATH="$PATH:$CARGO_HOME/bin" ENV PATH="$PATH:$CARGO_HOME/bin"
ENV DEBIAN_FRONTEND=noninteractive
# Install all CI dependencies # 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 \ RUN apt-get update \
&& apt-get -yq upgrade \ && apt-get -yq upgrade \
&& apt-get install --no-install-recommends -yq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
build-essential \ build-essential \
bc \ bc \
curl \ curl \
wget \ wget \
sudo \ sudo \
mtools \ mtools \
musl-tools \ musl-tools \
libssl-dev \ libssl-dev \
pkg-config \ pkg-config \
flex \ flex \
bison \ bison \
libelf-dev \ libelf-dev \
qemu-utils \ qemu-utils \
libglib2.0-dev \ libglib2.0-dev \
libpixman-1-dev \ libpixman-1-dev \
libseccomp-dev \ libseccomp-dev \
libcap-ng-dev \ libcap-ng-dev \
socat \ socat \
dosfstools \ dosfstools \
cpio \ cpio \
python \ python \
python3 \ python3 \
python3-setuptools \ python3-setuptools \
ntfs-3g \ ntfs-3g \
python3-distutils \ openvswitch-switch-dpdk \
uuid-dev \ python3-distutils \
iperf3 \ uuid-dev \
zip \ iperf3 \
git-core \ zip \
dnsmasq \ git-core \
dmsetup \ dnsmasq \
ca-certificates \ dmsetup \
unzip \
iproute2 \
dbus \
&& apt-get install openvswitch-switch-dpdk -yq \
&& apt-get clean \ && 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 RUN update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
# hadolint ignore=DL3008
RUN if [ "$TARGETARCH" = "amd64" ]; then \ RUN if [ "$TARGETARCH" = "amd64" ]; then \
apt-get update \ apt-get update \
&& apt-get -yq upgrade \ && apt-get -yq upgrade \
&& apt-get install --no-install-recommends -yq gcc-multilib gawk \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq gcc-multilib gawk \
libtool expect gnutls-dev gnutls-bin libfuse-dev \ libtool expect gnutls-dev gnutls-bin libfuse-dev \
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \ libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
net-tools softhsm2 \ net-tools softhsm2 \
&& apt-get clean \ && 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
# hadolint ignore=DL3008
RUN if [ "$TARGETARCH" = "arm64" ]; then \ RUN if [ "$TARGETARCH" = "arm64" ]; then \
# On AArch64, `setcap` binary should be installed via `libcap2-bin`. # On AArch64, `setcap` binary should be installed via `libcap2-bin`.
# The `setcap` binary is used in integration tests. # The `setcap` binary is used in integration tests.
@@ -83,7 +72,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
# kernel (any version) image in `/boot` and modules in `/lib/modules`. # kernel (any version) image in `/boot` and modules in `/lib/modules`.
apt-get update \ apt-get update \
&& apt-get -yq upgrade \ && apt-get -yq upgrade \
&& apt-get install --no-install-recommends -yq \ && DEBIAN_FRONTEND=noninteractive apt-get install -yq \
libcap2-bin \ libcap2-bin \
libguestfs-tools \ libguestfs-tools \
linux-image-generic \ linux-image-generic \
@@ -93,12 +82,11 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
perl \ perl \
texinfo \ texinfo \
&& apt-get clean \ && 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 # Fix the libssl-dev install
# hadolint ignore=SC2155
RUN export ARCH="$(uname -m)" \ 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_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 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/ ENV AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
@@ -106,10 +94,9 @@ ENV AARCH64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
ENV OPENSSL_INCLUDE_DIR=/usr/include/ ENV OPENSSL_INCLUDE_DIR=/usr/include/
# Install the rust toolchain # Install the rust toolchain
# hadolint ignore=DL4006,SC2155
RUN export ARCH="$(uname -m)" \ 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" \ && 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 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 rustfmt; fi \
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \ && if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
@@ -119,14 +106,12 @@ RUN export ARCH="$(uname -m)" \
&& ln -s "$CARGO_GIT_REGISTRY_DIR" "$CARGO_HOME/git" && ln -s "$CARGO_GIT_REGISTRY_DIR" "$CARGO_HOME/git"
# Set the rust environment # Set the rust environment
# hadolint ignore=SC2016 RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
RUN echo 'source $CARGO_HOME/env' >> "$HOME"/.bashrc \ && mkdir $HOME/.cargo \
&& mkdir "$HOME"/.cargo \ && ln -s $CARGO_HOME/env $HOME/.cargo/env
&& ln -s $CARGO_HOME/env "$HOME"/.cargo/env
# install SPDK NVMe # install SPDK NVMe
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk' # only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
# hadolint ignore=DL3003,SC2046
RUN if [ "$TARGETARCH" = "amd64" ]; then \ RUN if [ "$TARGETARCH" = "amd64" ]; then \
git clone https://github.com/spdk/spdk \ git clone https://github.com/spdk/spdk \
&& cd spdk \ && cd spdk \
@@ -136,7 +121,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
&& ./scripts/pkgdep.sh \ && ./scripts/pkgdep.sh \
&& apt-get clean \ && apt-get clean \
&& ./configure --with-vfio-user \ && ./configure --with-vfio-user \
&& make -j $(nproc) \ && make -j `nproc` \
&& mkdir /usr/local/bin/spdk-nvme \ && mkdir /usr/local/bin/spdk-nvme \
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \ && cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \ && cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
@@ -144,7 +129,6 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
&& cd .. && rm -rf spdk; fi && cd .. && rm -rf spdk; fi
# install swtpm only for x86_64 arch # install swtpm only for x86_64 arch
# hadolint ignore=DL3003
RUN if [ "$TARGETARCH" = "amd64" ]; then \ RUN if [ "$TARGETARCH" = "amd64" ]; then \
git clone https://github.com/stefanberger/libtpms libtpms_build \ git clone https://github.com/stefanberger/libtpms libtpms_build \
&& cd libtpms_build \ && cd libtpms_build \
@@ -165,7 +149,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
# install ethr tool for performance tests # install ethr tool for performance tests
RUN if [ "$TARGETARCH" = "amd64" ]; then \ 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 \ && unzip ethr_linux.zip \
&& cp ethr /usr/local/bin \ && cp ethr /usr/local/bin \
&& rm ethr_linux.zip; fi && rm ethr_linux.zip; fi

View File

@@ -1,6 +1,6 @@
# #
# Automatically generated file; DO NOT EDIT. # Automatically generated file; DO NOT EDIT.
# Linux/arm64 6.2.0 Kernel Configuration # Linux/arm64 6.1.6 Kernel Configuration
# #
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0" CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
CONFIG_CC_IS_GCC=y CONFIG_CC_IS_GCC=y
@@ -55,6 +55,7 @@ CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_IRQ_IPI=y CONFIG_GENERIC_IRQ_IPI=y
CONFIG_GENERIC_MSI_IRQ=y CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y CONFIG_IRQ_MSI_IOMMU=y
CONFIG_IRQ_FORCED_THREADING=y CONFIG_IRQ_FORCED_THREADING=y
CONFIG_SPARSE_IRQ=y CONFIG_SPARSE_IRQ=y
@@ -202,7 +203,6 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y CONFIG_LD_ORPHAN_WARN=y
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
CONFIG_SYSCTL=y CONFIG_SYSCTL=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_EXPERT=y CONFIG_EXPERT=y
@@ -227,7 +227,6 @@ CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_SELFTEST is not set
# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_BASE_RELATIVE=y CONFIG_KALLSYMS_BASE_RELATIVE=y
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
@@ -250,7 +249,7 @@ CONFIG_PERF_EVENTS=y
# end of General setup # end of General setup
CONFIG_ARM64=y CONFIG_ARM64=y
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_64BIT=y CONFIG_64BIT=y
CONFIG_MMU=y CONFIG_MMU=y
CONFIG_ARM64_PAGE_SHIFT=12 CONFIG_ARM64_PAGE_SHIFT=12
@@ -350,7 +349,6 @@ CONFIG_ARM64_ERRATUM_2054223=y
CONFIG_ARM64_ERRATUM_2067961=y CONFIG_ARM64_ERRATUM_2067961=y
CONFIG_ARM64_ERRATUM_2441009=y CONFIG_ARM64_ERRATUM_2441009=y
CONFIG_ARM64_ERRATUM_2457168=y CONFIG_ARM64_ERRATUM_2457168=y
CONFIG_ARM64_ERRATUM_2645198=y
CONFIG_CAVIUM_ERRATUM_22375=y CONFIG_CAVIUM_ERRATUM_22375=y
CONFIG_CAVIUM_ERRATUM_23144=y CONFIG_CAVIUM_ERRATUM_23144=y
CONFIG_CAVIUM_ERRATUM_23154=y CONFIG_CAVIUM_ERRATUM_23154=y
@@ -378,7 +376,7 @@ CONFIG_ARM64_PA_BITS=48
# CONFIG_CPU_BIG_ENDIAN is not set # CONFIG_CPU_BIG_ENDIAN is not set
CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SCHED_MC=y CONFIG_SCHED_MC=y
# CONFIG_SCHED_CLUSTER is not set CONFIG_SCHED_CLUSTER is not set
CONFIG_SCHED_SMT=y CONFIG_SCHED_SMT=y
CONFIG_NR_CPUS=128 CONFIG_NR_CPUS=128
CONFIG_HOTPLUG_CPU=y CONFIG_HOTPLUG_CPU=y
@@ -473,6 +471,7 @@ CONFIG_RANDOMIZE_BASE=y
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
CONFIG_STACKPROTECTOR_PER_TASK=y CONFIG_STACKPROTECTOR_PER_TASK=y
CONFIG_ARCH_NR_GPIO=0
# end of Kernel Features # end of Kernel Features
# #
@@ -560,7 +559,6 @@ CONFIG_ACPI_GENERIC_GSI=y
CONFIG_ACPI_CCA_REQUIRED=y CONFIG_ACPI_CCA_REQUIRED=y
# CONFIG_ACPI_DEBUGGER is not set # CONFIG_ACPI_DEBUGGER is not set
CONFIG_ACPI_SPCR_TABLE=y CONFIG_ACPI_SPCR_TABLE=y
# CONFIG_ACPI_FPDT is not set
# CONFIG_ACPI_EC_DEBUGFS is not set # CONFIG_ACPI_EC_DEBUGFS is not set
# CONFIG_ACPI_AC is not set # CONFIG_ACPI_AC is not set
# CONFIG_ACPI_BATTERY is not set # CONFIG_ACPI_BATTERY is not set
@@ -593,10 +591,8 @@ CONFIG_HAVE_ACPI_APEI=y
# CONFIG_ACPI_PFRUT is not set # CONFIG_ACPI_PFRUT is not set
CONFIG_ACPI_IORT=y CONFIG_ACPI_IORT=y
CONFIG_ACPI_GTDT=y CONFIG_ACPI_GTDT=y
CONFIG_ACPI_APMT=y
CONFIG_ACPI_PPTT=y CONFIG_ACPI_PPTT=y
# CONFIG_ACPI_PCC is not set # CONFIG_ACPI_PCC is not set
# CONFIG_ACPI_FFH is not set
# CONFIG_PMIC_OPREGION is not set # CONFIG_PMIC_OPREGION is not set
CONFIG_ACPI_VIOT=y CONFIG_ACPI_VIOT=y
# CONFIG_ACPI_PRMT is not set # CONFIG_ACPI_PRMT is not set
@@ -605,9 +601,6 @@ CONFIG_HAVE_KVM=y
CONFIG_HAVE_KVM_IRQCHIP=y CONFIG_HAVE_KVM_IRQCHIP=y
CONFIG_HAVE_KVM_IRQFD=y CONFIG_HAVE_KVM_IRQFD=y
CONFIG_HAVE_KVM_IRQ_ROUTING=y CONFIG_HAVE_KVM_IRQ_ROUTING=y
CONFIG_HAVE_KVM_DIRTY_RING=y
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP=y
CONFIG_HAVE_KVM_EVENTFD=y CONFIG_HAVE_KVM_EVENTFD=y
CONFIG_KVM_MMIO=y CONFIG_KVM_MMIO=y
CONFIG_HAVE_KVM_MSI=y CONFIG_HAVE_KVM_MSI=y
@@ -661,7 +654,6 @@ CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
CONFIG_MMU_GATHER_TABLE_FREE=y CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y CONFIG_HAVE_CMPXCHG_DOUBLE=y
@@ -726,7 +718,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling # end of GCOV-based kernel profiling
CONFIG_HAVE_GCC_PLUGINS=y CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_FUNCTION_ALIGNMENT=0
# end of General architecture-dependent options # end of General architecture-dependent options
CONFIG_RT_MUTEXES=y CONFIG_RT_MUTEXES=y
@@ -893,8 +884,7 @@ CONFIG_ZSMALLOC_STAT=y
# #
# CONFIG_SLAB is not set # CONFIG_SLAB is not set
CONFIG_SLUB=y CONFIG_SLUB=y
# CONFIG_SLOB_DEPRECATED is not set # CONFIG_SLOB is not set
# CONFIG_SLUB_TINY is not set
CONFIG_SLAB_MERGE_DEFAULT=y CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SLAB_FREELIST_RANDOM is not set # CONFIG_SLAB_FREELIST_RANDOM is not set
CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y
@@ -961,7 +951,6 @@ CONFIG_ZONE_DMA32=y
CONFIG_ZONE_DEVICE=y CONFIG_ZONE_DEVICE=y
# CONFIG_DEVICE_PRIVATE is not set # CONFIG_DEVICE_PRIVATE is not set
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
CONFIG_ARCH_USES_PG_ARCH_X=y
CONFIG_VM_EVENT_COUNTERS=y CONFIG_VM_EVENT_COUNTERS=y
CONFIG_PERCPU_STATS=y CONFIG_PERCPU_STATS=y
# CONFIG_GUP_TEST is not set # CONFIG_GUP_TEST is not set
@@ -1133,6 +1122,7 @@ CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set # CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set # CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y CONFIG_PCI_QUIRKS=y
CONFIG_PCI_DEBUG=y CONFIG_PCI_DEBUG=y
CONFIG_PCI_STUB=y CONFIG_PCI_STUB=y
@@ -1282,6 +1272,7 @@ CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB=y CONFIG_EFI_GENERIC_STUB=y
# CONFIG_EFI_ZBOOT is not set # CONFIG_EFI_ZBOOT is not set
CONFIG_EFI_ARMSTUB_DTB_LOADER=y CONFIG_EFI_ARMSTUB_DTB_LOADER=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set # CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set # CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set # CONFIG_EFI_TEST is not set
@@ -1335,7 +1326,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
CONFIG_ZRAM_DEF_COMP="lzo-rle" CONFIG_ZRAM_DEF_COMP="lzo-rle"
# CONFIG_ZRAM_WRITEBACK is not set # CONFIG_ZRAM_WRITEBACK is not set
# CONFIG_ZRAM_MEMORY_TRACKING is not set # CONFIG_ZRAM_MEMORY_TRACKING is not set
# CONFIG_ZRAM_MULTI_COMP is not set
CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_DRBD is not set # CONFIG_BLK_DEV_DRBD is not set
@@ -1586,7 +1576,6 @@ CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set # CONFIG_LEGACY_PTYS is not set
# CONFIG_LEGACY_TIOCSTI is not set
# CONFIG_LDISC_AUTOLOAD is not set # CONFIG_LDISC_AUTOLOAD is not set
# #
@@ -1662,6 +1651,8 @@ CONFIG_DEVMEM=y
CONFIG_DEVPORT=y CONFIG_DEVPORT=y
# CONFIG_TCG_TPM is not set # CONFIG_TCG_TPM is not set
# CONFIG_XILLYBUS is not set # CONFIG_XILLYBUS is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# end of Character devices # end of Character devices
# #
@@ -1750,7 +1741,6 @@ CONFIG_GPIO_PL061=y
# Virtual GPIO drivers # Virtual GPIO drivers
# #
# CONFIG_GPIO_AGGREGATOR is not set # CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_MOCKUP is not set # CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set # CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set # CONFIG_GPIO_SIM is not set
@@ -2168,10 +2158,9 @@ CONFIG_UIO_DMEM_GENIRQ=y
# CONFIG_UIO_PRUSS is not set # CONFIG_UIO_PRUSS is not set
# CONFIG_UIO_MF624 is not set # CONFIG_UIO_MF624 is not set
CONFIG_VFIO=y CONFIG_VFIO=y
CONFIG_VFIO_CONTAINER=y
CONFIG_VFIO_IOMMU_TYPE1=y CONFIG_VFIO_IOMMU_TYPE1=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_VIRQFD=y CONFIG_VFIO_VIRQFD=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_PCI_CORE=y CONFIG_VFIO_PCI_CORE=y
CONFIG_VFIO_PCI_MMAP=y CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y CONFIG_VFIO_PCI_INTX=y
@@ -2270,7 +2259,6 @@ CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set # CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
CONFIG_OF_IOMMU=y CONFIG_OF_IOMMU=y
CONFIG_IOMMU_DMA=y CONFIG_IOMMU_DMA=y
# CONFIG_IOMMUFD is not set
# CONFIG_ARM_SMMU is not set # CONFIG_ARM_SMMU is not set
# CONFIG_ARM_SMMU_V3 is not set # CONFIG_ARM_SMMU_V3 is not set
CONFIG_VIRTIO_IOMMU=y CONFIG_VIRTIO_IOMMU=y
@@ -2407,7 +2395,6 @@ CONFIG_ARM_PMU_ACPI=y
# CONFIG_HISI_PMU is not set # CONFIG_HISI_PMU is not set
# CONFIG_HISI_PCIE_PMU is not set # CONFIG_HISI_PCIE_PMU is not set
# CONFIG_HNS3_PMU is not set # CONFIG_HNS3_PMU is not set
# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set
# end of Performance monitor support # end of Performance monitor support
CONFIG_RAS=y CONFIG_RAS=y
@@ -2583,10 +2570,8 @@ CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_FILE_CACHE=y CONFIG_SQUASHFS_FILE_CACHE=y
# CONFIG_SQUASHFS_FILE_DIRECT is not set # CONFIG_SQUASHFS_FILE_DIRECT is not set
CONFIG_SQUASHFS_DECOMP_SINGLE=y CONFIG_SQUASHFS_DECOMP_SINGLE=y
# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set # CONFIG_SQUASHFS_DECOMP_MULTI is not set
CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y # CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
# CONFIG_SQUASHFS_XATTR is not set # CONFIG_SQUASHFS_XATTR is not set
CONFIG_SQUASHFS_ZLIB=y CONFIG_SQUASHFS_ZLIB=y
# CONFIG_SQUASHFS_LZ4 is not set # CONFIG_SQUASHFS_LZ4 is not set
@@ -2725,6 +2710,7 @@ CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_USER is not set # CONFIG_CRYPTO_USER is not set
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set # CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y CONFIG_CRYPTO_NULL2=y
# CONFIG_CRYPTO_PCRYPT is not set # CONFIG_CRYPTO_PCRYPT is not set
@@ -2886,8 +2872,6 @@ CONFIG_CRYPTO_USER_API_RNG=y
# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set # CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set # CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set # CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
# CONFIG_CRYPTO_SM4_ARM64_CE_CCM is not set
# CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set
# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set # CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set
# end of Accelerated Cryptographic Algorithms for CPU (arm64) # end of Accelerated Cryptographic Algorithms for CPU (arm64)
@@ -2926,7 +2910,6 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
# #
CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
# CONFIG_CRYPTO_LIB_CHACHA is not set # CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set # CONFIG_CRYPTO_LIB_CURVE25519 is not set
@@ -3062,8 +3045,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_DEBUG_INFO_DWARF4 is not set # CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set # CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set # CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y # CONFIG_DEBUG_INFO_COMPRESSED is not set
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_SPLIT is not set # CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set # CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set # CONFIG_GDB_SCRIPTS is not set
@@ -3224,7 +3206,7 @@ CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
CONFIG_HAVE_FUNCTION_TRACER=y CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_HAVE_C_RECORDMCOUNT=y
@@ -3263,6 +3245,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HEXDUMP is not set # CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set # CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set # CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set # CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set # CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set # CONFIG_TEST_SCANF is not set
@@ -3271,6 +3254,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_XARRAY is not set # CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_MAPLE_TREE is not set # CONFIG_TEST_MAPLE_TREE is not set
# CONFIG_TEST_RHASHTABLE is not set # CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set # CONFIG_TEST_IDA is not set
# CONFIG_FIND_BIT_BENCHMARK is not set # CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set # CONFIG_TEST_FIRMWARE is not set

View File

@@ -1,18 +1,18 @@
# #
# Automatically generated file; DO NOT EDIT. # Automatically generated file; DO NOT EDIT.
# Linux/x86 6.2.0 Kernel Configuration # Linux/x86 6.1.6 Kernel Configuration
# #
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0" CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4)"
CONFIG_CC_IS_GCC=y CONFIG_CC_IS_GCC=y
CONFIG_GCC_VERSION=110300 CONFIG_GCC_VERSION=120201
CONFIG_CLANG_VERSION=0 CONFIG_CLANG_VERSION=0
CONFIG_AS_IS_GNU=y CONFIG_AS_IS_GNU=y
CONFIG_AS_VERSION=23800 CONFIG_AS_VERSION=23700
CONFIG_LD_IS_BFD=y CONFIG_LD_IS_BFD=y
CONFIG_LD_VERSION=23800 CONFIG_LD_VERSION=23700
CONFIG_LLD_VERSION=0 CONFIG_LLD_VERSION=0
CONFIG_RUST_IS_AVAILABLE=y
CONFIG_CC_CAN_LINK=y CONFIG_CC_CAN_LINK=y
CONFIG_CC_CAN_LINK_STATIC=y
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
CONFIG_CC_HAS_ASM_INLINE=y CONFIG_CC_HAS_ASM_INLINE=y
@@ -70,6 +70,7 @@ CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_IRQ_DOMAIN=y CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_GENERIC_MSI_IRQ=y CONFIG_GENERIC_MSI_IRQ=y
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
CONFIG_IRQ_MSI_IOMMU=y CONFIG_IRQ_MSI_IOMMU=y
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
@@ -227,7 +228,6 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_LD_ORPHAN_WARN=y CONFIG_LD_ORPHAN_WARN=y
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
CONFIG_SYSCTL=y CONFIG_SYSCTL=y
CONFIG_SYSCTL_EXCEPTION_TRACE=y CONFIG_SYSCTL_EXCEPTION_TRACE=y
CONFIG_HAVE_PCSPKR_PLATFORM=y CONFIG_HAVE_PCSPKR_PLATFORM=y
@@ -254,7 +254,6 @@ CONFIG_IO_URING=y
CONFIG_ADVISE_SYSCALLS=y CONFIG_ADVISE_SYSCALLS=y
CONFIG_MEMBARRIER=y CONFIG_MEMBARRIER=y
CONFIG_KALLSYMS=y CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_SELFTEST is not set
# CONFIG_KALLSYMS_ALL is not set # CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
CONFIG_KALLSYMS_BASE_RELATIVE=y CONFIG_KALLSYMS_BASE_RELATIVE=y
@@ -275,6 +274,7 @@ CONFIG_PERF_EVENTS=y
# end of Kernel Performance Events And Counters # end of Kernel Performance Events And Counters
# CONFIG_PROFILING is not set # CONFIG_PROFILING is not set
# CONFIG_RUST is not set
# end of General setup # end of General setup
CONFIG_64BIT=y CONFIG_64BIT=y
@@ -294,6 +294,7 @@ CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_ARCH_HAS_CPU_RELAX=y CONFIG_ARCH_HAS_CPU_RELAX=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_NR_GPIO=1024
CONFIG_ARCH_SUSPEND_POSSIBLE=y CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_AUDIT_ARCH=y CONFIG_AUDIT_ARCH=y
CONFIG_X86_64_SMP=y CONFIG_X86_64_SMP=y
@@ -421,10 +422,7 @@ CONFIG_X86_INTEL_TSX_MODE_OFF=y
# CONFIG_X86_SGX is not set # CONFIG_X86_SGX is not set
CONFIG_EFI=y CONFIG_EFI=y
CONFIG_EFI_STUB=y CONFIG_EFI_STUB=y
# CONFIG_EFI_HANDOVER_PROTOCOL is not set
# CONFIG_EFI_MIXED is not set # CONFIG_EFI_MIXED is not set
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_HZ_100 is not set # CONFIG_HZ_100 is not set
CONFIG_HZ_250=y CONFIG_HZ_250=y
# CONFIG_HZ_300 is not set # CONFIG_HZ_300 is not set
@@ -457,20 +455,11 @@ CONFIG_HAVE_LIVEPATCH=y
CONFIG_CC_HAS_SLS=y CONFIG_CC_HAS_SLS=y
CONFIG_CC_HAS_RETURN_THUNK=y CONFIG_CC_HAS_RETURN_THUNK=y
CONFIG_CC_HAS_ENTRY_PADDING=y
CONFIG_FUNCTION_PADDING_CFI=11
CONFIG_FUNCTION_PADDING_BYTES=16
CONFIG_CALL_PADDING=y
CONFIG_HAVE_CALL_THUNKS=y
CONFIG_CALL_THUNKS=y
CONFIG_PREFIX_SYMBOLS=y
CONFIG_SPECULATION_MITIGATIONS=y CONFIG_SPECULATION_MITIGATIONS=y
CONFIG_PAGE_TABLE_ISOLATION=y CONFIG_PAGE_TABLE_ISOLATION=y
CONFIG_RETPOLINE=y CONFIG_RETPOLINE=y
CONFIG_RETHUNK=y CONFIG_RETHUNK=y
CONFIG_CPU_UNRET_ENTRY=y CONFIG_CPU_UNRET_ENTRY=y
CONFIG_CALL_DEPTH_TRACKING=y
# CONFIG_CALL_THUNKS_DEBUG is not set
CONFIG_CPU_IBPB_ENTRY=y CONFIG_CPU_IBPB_ENTRY=y
CONFIG_CPU_IBRS_ENTRY=y CONFIG_CPU_IBRS_ENTRY=y
# CONFIG_SLS is not set # CONFIG_SLS is not set
@@ -544,7 +533,6 @@ CONFIG_HAVE_ACPI_APEI_NMI=y
# CONFIG_ACPI_CONFIGFS is not set # CONFIG_ACPI_CONFIGFS is not set
# CONFIG_ACPI_PFRUT is not set # CONFIG_ACPI_PFRUT is not set
# CONFIG_ACPI_PCC is not set # CONFIG_ACPI_PCC is not set
# CONFIG_ACPI_FFH is not set
# CONFIG_PMIC_OPREGION is not set # CONFIG_PMIC_OPREGION is not set
CONFIG_ACPI_VIOT=y CONFIG_ACPI_VIOT=y
# CONFIG_ACPI_PRMT is not set # CONFIG_ACPI_PRMT is not set
@@ -640,7 +628,6 @@ CONFIG_KVM=y
# CONFIG_KVM_WERROR is not set # CONFIG_KVM_WERROR is not set
CONFIG_KVM_INTEL=y CONFIG_KVM_INTEL=y
# CONFIG_KVM_AMD is not set # CONFIG_KVM_AMD is not set
CONFIG_KVM_SMM=y
# CONFIG_KVM_XEN is not set # CONFIG_KVM_XEN is not set
CONFIG_AS_AVX512=y CONFIG_AS_AVX512=y
CONFIG_AS_SHA1_NI=y CONFIG_AS_SHA1_NI=y
@@ -697,7 +684,6 @@ CONFIG_MMU_GATHER_TABLE_FREE=y
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
CONFIG_MMU_GATHER_MERGE_VMAS=y CONFIG_MMU_GATHER_MERGE_VMAS=y
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
CONFIG_HAVE_CMPXCHG_LOCAL=y CONFIG_HAVE_CMPXCHG_LOCAL=y
CONFIG_HAVE_CMPXCHG_DOUBLE=y CONFIG_HAVE_CMPXCHG_DOUBLE=y
@@ -779,9 +765,6 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# end of GCOV-based kernel profiling # end of GCOV-based kernel profiling
CONFIG_HAVE_GCC_PLUGINS=y CONFIG_HAVE_GCC_PLUGINS=y
CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FUNCTION_ALIGNMENT_16B=y
CONFIG_FUNCTION_ALIGNMENT=16
# end of General architecture-dependent options # end of General architecture-dependent options
CONFIG_RT_MUTEXES=y CONFIG_RT_MUTEXES=y
@@ -899,8 +882,7 @@ CONFIG_ZSMALLOC_STAT=y
# #
# CONFIG_SLAB is not set # CONFIG_SLAB is not set
CONFIG_SLUB=y CONFIG_SLUB=y
# CONFIG_SLOB_DEPRECATED is not set # CONFIG_SLOB is not set
# CONFIG_SLUB_TINY is not set
CONFIG_SLAB_MERGE_DEFAULT=y CONFIG_SLAB_MERGE_DEFAULT=y
# CONFIG_SLAB_FREELIST_RANDOM is not set # CONFIG_SLAB_FREELIST_RANDOM is not set
CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_SLAB_FREELIST_HARDENED=y
@@ -975,6 +957,7 @@ CONFIG_SECRETMEM=y
CONFIG_USERFAULTFD=y CONFIG_USERFAULTFD=y
CONFIG_HAVE_ARCH_USERFAULTFD_WP=y CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
CONFIG_PTE_MARKER=y
CONFIG_PTE_MARKER_UFFD_WP=y CONFIG_PTE_MARKER_UFFD_WP=y
# CONFIG_LRU_GEN is not set # CONFIG_LRU_GEN is not set
@@ -1139,6 +1122,7 @@ CONFIG_PCIE_PME=y
# CONFIG_PCIE_DPC is not set # CONFIG_PCIE_DPC is not set
# CONFIG_PCIE_PTM is not set # CONFIG_PCIE_PTM is not set
CONFIG_PCI_MSI=y CONFIG_PCI_MSI=y
CONFIG_PCI_MSI_IRQ_DOMAIN=y
CONFIG_PCI_QUIRKS=y CONFIG_PCI_QUIRKS=y
CONFIG_PCI_DEBUG=y CONFIG_PCI_DEBUG=y
CONFIG_PCI_STUB=y CONFIG_PCI_STUB=y
@@ -1267,8 +1251,11 @@ CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
# EFI (Extensible Firmware Interface) Support # EFI (Extensible Firmware Interface) Support
# #
CONFIG_EFI_ESRT=y CONFIG_EFI_ESRT=y
CONFIG_EFI_RUNTIME_MAP=y
# CONFIG_EFI_FAKE_MEMMAP is not set
CONFIG_EFI_DXE_MEM_ATTRIBUTES=y CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
CONFIG_EFI_RUNTIME_WRAPPERS=y CONFIG_EFI_RUNTIME_WRAPPERS=y
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
# CONFIG_EFI_BOOTLOADER_CONTROL is not set # CONFIG_EFI_BOOTLOADER_CONTROL is not set
# CONFIG_EFI_CAPSULE_LOADER is not set # CONFIG_EFI_CAPSULE_LOADER is not set
# CONFIG_EFI_TEST is not set # CONFIG_EFI_TEST is not set
@@ -1309,7 +1296,6 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
CONFIG_ZRAM_DEF_COMP="lzo-rle" CONFIG_ZRAM_DEF_COMP="lzo-rle"
# CONFIG_ZRAM_WRITEBACK is not set # CONFIG_ZRAM_WRITEBACK is not set
# CONFIG_ZRAM_MEMORY_TRACKING is not set # CONFIG_ZRAM_MEMORY_TRACKING is not set
# CONFIG_ZRAM_MULTI_COMP is not set
CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8 CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
# CONFIG_BLK_DEV_DRBD is not set # CONFIG_BLK_DEV_DRBD is not set
@@ -1564,7 +1550,6 @@ CONFIG_HW_CONSOLE=y
CONFIG_VT_HW_CONSOLE_BINDING=y CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_UNIX98_PTYS=y CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set # CONFIG_LEGACY_PTYS is not set
# CONFIG_LEGACY_TIOCSTI is not set
# CONFIG_LDISC_AUTOLOAD is not set # CONFIG_LDISC_AUTOLOAD is not set
# #
@@ -1639,6 +1624,8 @@ CONFIG_HANGCHECK_TIMER=y
# CONFIG_TCG_TPM is not set # CONFIG_TCG_TPM is not set
# CONFIG_TELCLOCK is not set # CONFIG_TELCLOCK is not set
# CONFIG_XILLYBUS is not set # CONFIG_XILLYBUS is not set
# CONFIG_RANDOM_TRUST_CPU is not set
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
# end of Character devices # end of Character devices
# #
@@ -1687,7 +1674,6 @@ CONFIG_GPIOLIB_IRQCHIP=y
CONFIG_GPIO_SYSFS=y CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_CDEV=y CONFIG_GPIO_CDEV=y
CONFIG_GPIO_CDEV_V1=y CONFIG_GPIO_CDEV_V1=y
CONFIG_GPIO_IDIO_16=y
# #
# Memory mapped GPIO drivers # Memory mapped GPIO drivers
@@ -1731,7 +1717,6 @@ CONFIG_GPIO_PCI_IDIO_16=y
# Virtual GPIO drivers # Virtual GPIO drivers
# #
# CONFIG_GPIO_AGGREGATOR is not set # CONFIG_GPIO_AGGREGATOR is not set
# CONFIG_GPIO_LATCH is not set
# CONFIG_GPIO_MOCKUP is not set # CONFIG_GPIO_MOCKUP is not set
# CONFIG_GPIO_VIRTIO is not set # CONFIG_GPIO_VIRTIO is not set
# CONFIG_GPIO_SIM is not set # CONFIG_GPIO_SIM is not set
@@ -1799,7 +1784,6 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0
# CONFIG_MAX63XX_WATCHDOG is not set # CONFIG_MAX63XX_WATCHDOG is not set
# CONFIG_ACQUIRE_WDT is not set # CONFIG_ACQUIRE_WDT is not set
# CONFIG_ADVANTECH_WDT is not set # CONFIG_ADVANTECH_WDT is not set
# CONFIG_ADVANTECH_EC_WDT is not set
# CONFIG_ALIM1535_WDT is not set # CONFIG_ALIM1535_WDT is not set
# CONFIG_ALIM7101_WDT is not set # CONFIG_ALIM7101_WDT is not set
# CONFIG_EBC_C384_WDT is not set # CONFIG_EBC_C384_WDT is not set
@@ -2140,10 +2124,9 @@ CONFIG_UIO_DMEM_GENIRQ=y
# CONFIG_UIO_MF624 is not set # CONFIG_UIO_MF624 is not set
# CONFIG_UIO_HV_GENERIC is not set # CONFIG_UIO_HV_GENERIC is not set
CONFIG_VFIO=y CONFIG_VFIO=y
CONFIG_VFIO_CONTAINER=y
CONFIG_VFIO_IOMMU_TYPE1=y CONFIG_VFIO_IOMMU_TYPE1=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_VIRQFD=y CONFIG_VFIO_VIRQFD=y
# CONFIG_VFIO_NOIOMMU is not set
CONFIG_VFIO_PCI_CORE=y CONFIG_VFIO_PCI_CORE=y
CONFIG_VFIO_PCI_MMAP=y CONFIG_VFIO_PCI_MMAP=y
CONFIG_VFIO_PCI_INTX=y CONFIG_VFIO_PCI_INTX=y
@@ -2219,7 +2202,6 @@ CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
CONFIG_IOMMU_DMA=y CONFIG_IOMMU_DMA=y
# CONFIG_AMD_IOMMU is not set # CONFIG_AMD_IOMMU is not set
# CONFIG_INTEL_IOMMU is not set # CONFIG_INTEL_IOMMU is not set
# CONFIG_IOMMUFD is not set
# CONFIG_IRQ_REMAP is not set # CONFIG_IRQ_REMAP is not set
CONFIG_HYPERV_IOMMU=y CONFIG_HYPERV_IOMMU=y
CONFIG_VIRTIO_IOMMU=y CONFIG_VIRTIO_IOMMU=y
@@ -2562,7 +2544,12 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
# #
# Memory initialization # Memory initialization
# #
CONFIG_INIT_STACK_NONE=y CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
# CONFIG_INIT_STACK_NONE is not set
# CONFIG_INIT_STACK_ALL_PATTERN is not set
CONFIG_INIT_STACK_ALL_ZERO=y
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set # CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set # CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
@@ -2598,6 +2585,7 @@ CONFIG_CRYPTO_MANAGER2=y
# CONFIG_CRYPTO_USER is not set # CONFIG_CRYPTO_USER is not set
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set # CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set # CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
CONFIG_CRYPTO_GF128MUL=y
CONFIG_CRYPTO_NULL=y CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_NULL2=y CONFIG_CRYPTO_NULL2=y
# CONFIG_CRYPTO_PCRYPT is not set # CONFIG_CRYPTO_PCRYPT is not set
@@ -2807,7 +2795,6 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
# #
CONFIG_CRYPTO_LIB_UTILS=y CONFIG_CRYPTO_LIB_UTILS=y
CONFIG_CRYPTO_LIB_AES=y CONFIG_CRYPTO_LIB_AES=y
CONFIG_CRYPTO_LIB_GF128MUL=y
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
# CONFIG_CRYPTO_LIB_CHACHA is not set # CONFIG_CRYPTO_LIB_CHACHA is not set
# CONFIG_CRYPTO_LIB_CURVE25519 is not set # CONFIG_CRYPTO_LIB_CURVE25519 is not set
@@ -2895,7 +2882,6 @@ CONFIG_FONT_8x16=y
CONFIG_SG_POOL=y CONFIG_SG_POOL=y
CONFIG_ARCH_HAS_PMEM_API=y CONFIG_ARCH_HAS_PMEM_API=y
CONFIG_MEMREGION=y CONFIG_MEMREGION=y
CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
CONFIG_ARCH_HAS_COPY_MC=y CONFIG_ARCH_HAS_COPY_MC=y
CONFIG_ARCH_STACKWALK=y CONFIG_ARCH_STACKWALK=y
@@ -2936,8 +2922,7 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_DEBUG_INFO_DWARF4 is not set # CONFIG_DEBUG_INFO_DWARF4 is not set
# CONFIG_DEBUG_INFO_DWARF5 is not set # CONFIG_DEBUG_INFO_DWARF5 is not set
# CONFIG_DEBUG_INFO_REDUCED is not set # CONFIG_DEBUG_INFO_REDUCED is not set
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y # CONFIG_DEBUG_INFO_COMPRESSED is not set
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_SPLIT is not set # CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set # CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set # CONFIG_GDB_SCRIPTS is not set
@@ -3113,7 +3098,6 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_FENTRY=y CONFIG_HAVE_FENTRY=y
CONFIG_HAVE_OBJTOOL_MCOUNT=y CONFIG_HAVE_OBJTOOL_MCOUNT=y
CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y
CONFIG_HAVE_C_RECORDMCOUNT=y CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
CONFIG_TRACING_SUPPORT=y CONFIG_TRACING_SUPPORT=y
@@ -3173,6 +3157,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_HEXDUMP is not set # CONFIG_TEST_HEXDUMP is not set
# CONFIG_STRING_SELFTEST is not set # CONFIG_STRING_SELFTEST is not set
# CONFIG_TEST_STRING_HELPERS is not set # CONFIG_TEST_STRING_HELPERS is not set
# CONFIG_TEST_STRSCPY is not set
# CONFIG_TEST_KSTRTOX is not set # CONFIG_TEST_KSTRTOX is not set
# CONFIG_TEST_PRINTF is not set # CONFIG_TEST_PRINTF is not set
# CONFIG_TEST_SCANF is not set # CONFIG_TEST_SCANF is not set
@@ -3181,6 +3166,7 @@ CONFIG_RUNTIME_TESTING_MENU=y
# CONFIG_TEST_XARRAY is not set # CONFIG_TEST_XARRAY is not set
# CONFIG_TEST_MAPLE_TREE is not set # CONFIG_TEST_MAPLE_TREE is not set
# CONFIG_TEST_RHASHTABLE is not set # CONFIG_TEST_RHASHTABLE is not set
# CONFIG_TEST_SIPHASH is not set
# CONFIG_TEST_IDA is not set # CONFIG_TEST_IDA is not set
# CONFIG_FIND_BIT_BENCHMARK is not set # CONFIG_FIND_BIT_BENCHMARK is not set
# CONFIG_TEST_FIRMWARE is not set # CONFIG_TEST_FIRMWARE is not set

View File

@@ -3,7 +3,7 @@ set -x
rm -f /tmp/ubuntu-cloudinit.img rm -f /tmp/ubuntu-cloudinit.img
mkdosfs -n CIDATA -C /tmp/ubuntu-cloudinit.img 8192 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/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/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/network-config ::

View File

@@ -6,8 +6,8 @@
CLI_NAME="Cloud Hypervisor" CLI_NAME="Cloud Hypervisor"
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor" CTR_IMAGE_TAG="cloudhypervisor/dev"
CTR_IMAGE_VERSION="20230620-0" CTR_IMAGE_VERSION="20230123-0"
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}" CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker" DOCKER_RUNTIME="docker"
@@ -172,11 +172,7 @@ process_volumes_args() {
cmd_help() { cmd_help() {
echo "" echo ""
echo "Cloud Hypervisor $(basename "$0")" echo "Cloud Hypervisor $(basename "$0")"
echo "Usage: $(basename "$0") [flags] <command> [<command args>]" echo "Usage: $(basename "$0") <command> [<command args>]"
echo ""
echo "Available flags":
echo ""
echo " --local Set the container image version being used to \"local\"."
echo "" echo ""
echo "Available commands:" echo "Available commands:"
echo "" echo ""
@@ -426,7 +422,7 @@ cmd_tests() {
--env USER="root" \ --env USER="root" \
--env CH_LIBC="${libc}" \ --env CH_LIBC="${libc}" \
"$CTR_IMAGE" \ "$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 fi
if [ "$integration_sgx" = true ]; then if [ "$integration_sgx" = true ]; then
@@ -539,7 +535,6 @@ cmd_tests() {
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \ --volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
--env USER="root" \ --env USER="root" \
--env CH_LIBC="${libc}" \ --env CH_LIBC="${libc}" \
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
"$CTR_IMAGE" \ "$CTR_IMAGE" \
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $? ./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
fi fi

View File

@@ -225,8 +225,8 @@ fi
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}" BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
export TARGET_CC="musl-gcc" 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 RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
fi fi
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
@@ -240,9 +240,7 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run" sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Both test_vfio and ovs-dpdk rely on hugepages # Both test_vfio and ovs-dpdk rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'` echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
# Run all direct kernel boot (Device Tree) test cases in mod `parallel` # Run all direct kernel boot (Device Tree) test cases in mod `parallel`
@@ -281,12 +279,4 @@ else
exit $RES exit $RES
fi 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 exit $RES

View File

@@ -56,8 +56,26 @@ popd
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches # Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux" VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then if [ ! -f "$VMLINUX_IMAGE" ]; then
build_custom_linux SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}" BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
@@ -71,9 +89,7 @@ fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# Test ovs-dpdk relies on hugepages # Test ovs-dpdk relies on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'` echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1

View File

@@ -45,7 +45,29 @@ if [ $? -ne 0 ]; then
fi fi
popd popd
build_custom_linux # Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then
SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}" BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS="" CFLAGS=""

View File

@@ -42,8 +42,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS="" CFLAGS=""
TARGET_CC="" TARGET_CC=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
TARGET_CC="musl-gcc" TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/" CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET

View File

@@ -7,45 +7,14 @@ source $(dirname "$0")/test-util.sh
process_common_args "$@" process_common_args "$@"
WORKLOADS_DIR="$HOME/workloads" WORKLOADS_DIR="$HOME/workloads"
mkdir -p "$WORKLOADS_DIR" FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
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="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME" FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then FW="$WORKLOADS_DIR/hypervisor-fw"
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
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux" VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
build_custom_linux if [ ! -f "$VMLINUX_IMAGE" ]; then
build_custom_linux
fi
BLK_IMAGE="$WORKLOADS_DIR/blk.img" BLK_IMAGE="$WORKLOADS_DIR/blk.img"
MNT_DIR="mount_image" MNT_DIR="mount_image"
@@ -64,7 +33,7 @@ VFIO_DIR="$WORKLOADS_DIR/vfio"
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img" VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
mkdir -p $VFIO_DIR mkdir -p $VFIO_DIR
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR cp $FOCAL_OS_IMAGE $VFIO_DIR
cp $FW $VFIO_DIR cp $FW $VFIO_DIR
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1 cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
@@ -83,9 +52,7 @@ cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR
# test_vfio rely on hugepages # test_vfio rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'` echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1

View File

@@ -24,8 +24,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS="" CFLAGS=""
TARGET_CC="" TARGET_CC=""
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
export TARGET_CC="musl-gcc" 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 RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
fi fi
# Check if the images are present # Check if the images are present

View File

@@ -26,8 +26,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS="" CFLAGS=""
TARGET_CC="" TARGET_CC=""
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
TARGET_CC="musl-gcc" TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/" CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi fi
# Check if the images are present # Check if the images are present

View File

@@ -169,9 +169,7 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run" sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Both test_vfio, ovs-dpdk and vDPA tests rely on hugepages # Both test_vfio, ovs-dpdk and vDPA tests rely on hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'` echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
# Update max locked memory to 'unlimited' to avoid issues with vDPA # Update max locked memory to 'unlimited' to avoid issues with vDPA
@@ -189,13 +187,4 @@ if [ $RES -eq 0 ]; then
RES=$? RES=$?
fi 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 exit $RES

View File

@@ -95,9 +95,7 @@ fi
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# setup hugepages # setup hugepages
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'` echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages sudo chmod a+rwX /dev/hugepages
if [ -n "$test_filter" ]; then if [ -n "$test_filter" ]; then
@@ -107,12 +105,7 @@ fi
# Ensure that git commands can be run in this directory (for metrics report) # Ensure that git commands can be run in this directory (for metrics report)
git config --global --add safe.directory $PWD git config --global --add safe.directory $PWD
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE` export RUST_BACKTRACE=1
if [ -z $RUST_BACKTRACE_VALUE ];then
export RUST_BACKTRACE=1
else
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
fi
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]} time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
RES=$? RES=$?

View File

@@ -22,4 +22,3 @@ fi
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1 cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
cargo test --doc --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1

View File

@@ -3,3 +3,4 @@ f1eccdc5e1b515dbad294426ab081b47ebfb97c0 focal-server-cloudimg-amd64-custom-2021
7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw 7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw
864c074e2f1bd753667a35188b510d83a1d62793 jammy-server-cloudimg-amd64-custom-20230119-0.qcow2 864c074e2f1bd753667a35188b510d83a1d62793 jammy-server-cloudimg-amd64-custom-20230119-0.qcow2
24358ee053f94e7f710ea4ce9e7a63eff2a1eb25 jammy-server-cloudimg-amd64-custom-20230119-0.raw 24358ee053f94e7f710ea4ce9e7a63eff2a1eb25 jammy-server-cloudimg-amd64-custom-20230119-0.raw

View File

@@ -46,7 +46,7 @@ build_custom_linux() {
ARCH=$(uname -m) ARCH=$(uname -m)
SRCDIR=$PWD SRCDIR=$PWD
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom" LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
LINUX_CUSTOM_BRANCH="ch-6.2" LINUX_CUSTOM_BRANCH="ch-6.1.6"
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git" LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH" checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"

View File

@@ -11,19 +11,13 @@ use argh::FromArgs;
use option_parser::{ByteSized, ByteSizedParseError}; use option_parser::{ByteSized, ByteSizedParseError};
use std::fmt; use std::fmt;
use std::io::Read; use std::io::Read;
use std::marker::PhantomData;
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::process; use std::process;
#[cfg(feature = "dbus_api")]
use zbus::{dbus_proxy, zvariant::Optional};
type ApiResult = Result<(), Error>;
#[derive(Debug)] #[derive(Debug)]
enum Error { enum Error {
HttpApiClient(ApiClientError), Connect(std::io::Error),
#[cfg(feature = "dbus_api")] ApiClient(ApiClientError),
DBusApiClient(zbus::Error),
InvalidMemorySize(ByteSizedParseError), InvalidMemorySize(ByteSizedParseError),
InvalidBalloonSize(ByteSizedParseError), InvalidBalloonSize(ByteSizedParseError),
AddDeviceConfig(vmm::config::Error), AddDeviceConfig(vmm::config::Error),
@@ -43,9 +37,8 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*; use Error::*;
match self { match self {
HttpApiClient(e) => e.fmt(f), ApiClient(e) => e.fmt(f),
#[cfg(feature = "dbus_api")] Connect(e) => write!(f, "Error opening HTTP socket: {e}"),
DBusApiClient(e) => write!(f, "Error D-Bus proxy: {e}"),
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"), InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"),
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"), InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"),
AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"), AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"),
@@ -63,430 +56,12 @@ impl fmt::Display for Error {
} }
} }
enum TargetApi<'a> { fn resize_api_command(
HttpApi(UnixStream, PhantomData<&'a ()>), socket: &mut UnixStream,
#[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(
desired_vcpus: Option<u8>, desired_vcpus: Option<u8>,
memory: &Option<String>, memory: &Option<String>,
balloon: &Option<String>, balloon: &Option<String>,
) -> Result<String, Error> { ) -> Result<(), Error> {
let desired_ram: Option<u64> = if let Some(memory) = memory { let desired_ram: Option<u64> = if let Some(memory) = memory {
Some( Some(
memory memory
@@ -515,10 +90,16 @@ fn resize_config(
desired_balloon, 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 { let resize_zone = vmm::api::VmResizeZoneData {
id: id.to_owned(), id: id.to_owned(),
desired_ram: size desired_ram: size
@@ -527,52 +108,89 @@ fn resize_zone_config(id: &str, size: &str) -> Result<String, Error> {
.0, .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 = 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 = let device_config =
vmm::config::UserDeviceConfig::parse(config).map_err(Error::AddUserDeviceConfig)?; 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() }; 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 = 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 = 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 = 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)?; 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 // 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 // process would not make any sense since the file descriptor may be
// represented with different values. // represented with different values.
let fds = net_config.fds.take().unwrap_or_default(); 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 = 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 = 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 { let snapshot_config = vmm::api::VmSnapshotConfig {
destination_url: String::from(url), 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 = 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 { let coredump_config = vmm::api::VmCoredumpData {
destination_url: String::from(destination_url), 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 { let receive_migration_data = vmm::api::VmReceiveMigrationData {
receiver_url: url.to_owned(), receiver_url: url.to_owned(),
}; };
simple_api_command(
serde_json::to_string(&receive_migration_data).unwrap() 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 { let send_migration_data = vmm::api::VmSendMigrationData {
destination_url: url.to_owned(), destination_url: url.to_owned(),
local, local,
}; };
simple_api_command(
serde_json::to_string(&send_migration_data).unwrap() 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(); let mut data = String::default();
if path == "-" { if path == "-" {
std::io::stdin() 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)?; 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)] #[derive(FromArgs, PartialEq, Debug)]
@@ -661,21 +419,6 @@ struct TopLevel {
#[argh(option, long = "api-socket")] #[argh(option, long = "api-socket")]
/// HTTP API socket path (UNIX domain socket) /// HTTP API socket path (UNIX domain socket)
api_socket: Option<String>, 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)] #[derive(FromArgs, PartialEq, Debug)]
@@ -945,56 +688,16 @@ fn main() {
let toplevel: TopLevel = argh::from_env(); let toplevel: TopLevel = argh::from_env();
if matches!(toplevel.command, SubCommandEnum::Version(_)) { if matches!(toplevel.command, SubCommandEnum::Version(_)) {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return; return;
} }
let mut target_api = match ( if toplevel.api_socket.is_none() {
&toplevel.api_socket, println!("Please specify --api-socket");
#[cfg(feature = "dbus_api")] process::exit(1)
&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 let Err(e) = target_api.do_command(&toplevel) { if let Err(e) = do_command(&toplevel) {
eprintln!("Error running command: {e}"); eprintln!("Error running command: {e}");
process::exit(1) process::exit(1)
}; };

View File

@@ -8,7 +8,7 @@ extern crate event_monitor;
use argh::FromArgs; use argh::FromArgs;
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use log::{warn, LevelFilter}; use log::LevelFilter;
use option_parser::OptionParser; use option_parser::OptionParser;
use seccompiler::SeccompAction; use seccompiler::SeccompAction;
use signal_hook::consts::SIGSYS; use signal_hook::consts::SIGSYS;
@@ -18,8 +18,6 @@ use std::os::unix::io::{FromRawFd, RawFd};
use std::sync::mpsc::channel; use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use thiserror::Error; use thiserror::Error;
#[cfg(feature = "dbus_api")]
use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
use vmm::config; use vmm::config;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
use vmm_sys_util::signal::block_signal; use vmm_sys_util::signal::block_signal;
@@ -35,8 +33,6 @@ enum Error {
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
#[error("Failed to create Debug EventFd: {0}")] #[error("Failed to create Debug EventFd: {0}")]
CreateDebugEventFd(#[source] std::io::Error), CreateDebugEventFd(#[source] std::io::Error),
#[error("Failed to create exit EventFd: {0}")]
CreateExitEventFd(#[source] std::io::Error),
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")] #[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
CreateHypervisor(#[source] hypervisor::HypervisorError), CreateHypervisor(#[source] hypervisor::HypervisorError),
#[error("Failed to start the VMM thread: {0}")] #[error("Failed to start the VMM thread: {0}")]
@@ -59,12 +55,6 @@ enum Error {
ParsingApiSocket(std::num::ParseIntError), ParsingApiSocket(std::num::ParseIntError),
#[error("Error parsing --event-monitor: {0}")] #[error("Error parsing --event-monitor: {0}")]
ParsingEventMonitor(option_parser::OptionParserError), 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")] #[error("Error parsing --event-monitor: path or fd required")]
BareEventMonitor, BareEventMonitor,
#[error("Error doing event monitor I/O: {0}")] #[error("Error doing event monitor I/O: {0}")]
@@ -100,9 +90,9 @@ impl log::Log for Logger {
let duration = now.duration_since(self.start); let duration = now.duration_since(self.start);
if record.file().is_some() && record.line().is_some() { if record.file().is_some() && record.line().is_some() {
write!( writeln!(
*(*(self.output.lock().unwrap())), *(*(self.output.lock().unwrap())),
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n", "cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}",
duration, duration,
std::thread::current().name().unwrap_or("anonymous"), std::thread::current().name().unwrap_or("anonymous"),
record.level(), record.level(),
@@ -111,9 +101,9 @@ impl log::Log for Logger {
record.args() record.args()
) )
} else { } else {
write!( writeln!(
*(*(self.output.lock().unwrap())), *(*(self.output.lock().unwrap())),
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n", "cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}",
duration, duration,
std::thread::current().name().unwrap_or("anonymous"), std::thread::current().name().unwrap_or("anonymous"),
record.level(), record.level(),
@@ -146,19 +136,19 @@ fn default_rng() -> String {
/// Launch a cloud-hypervisor VMM. /// Launch a cloud-hypervisor VMM.
pub struct TopLevel { pub struct TopLevel {
#[argh(option, long = "cpus", default = "default_vcpus()")] #[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, cpus: String,
#[argh(option, long = "platform")] #[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>, platform: Option<String>,
#[argh(option, long = "memory", default = "default_memory()")] #[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, memory: String,
#[argh(option, long = "memory-zone")] #[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>, memory_zone: Vec<String>,
#[argh(option, long = "firmware")] #[argh(option, long = "firmware")]
@@ -178,27 +168,27 @@ pub struct TopLevel {
cmdline: Option<String>, cmdline: Option<String>,
#[argh(option, long = "disk")] #[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>, disk: Vec<String>,
#[argh(option, long = "net")] #[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>, net: Vec<String>,
#[argh(option, long = "rng", default = "default_rng()")] #[argh(option, long = "rng", default = "default_rng()")]
/// src=<entropy_source_path>, iommu=on|off /// src=<entropy_source_path>,iommu=on|off
rng: String, rng: String,
#[argh(option, long = "balloon")] #[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>, balloon: Option<String>,
#[argh(option, long = "fs")] #[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>, fs: Vec<String>,
#[argh(option, long = "pmem")] #[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>, pmem: Vec<String>,
#[argh(option, long = "serial", default = "String::from(\"null\")")] #[argh(option, long = "serial", default = "String::from(\"null\")")]
@@ -206,27 +196,27 @@ pub struct TopLevel {
serial: String, serial: String,
#[argh(option, long = "console", default = "String::from(\"tty\")")] #[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, console: String,
#[argh(option, long = "device")] #[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>, device: Vec<String>,
#[argh(option, long = "user-device")] #[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>, user_device: Vec<String>,
#[argh(option, long = "vdpa")] #[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>, vdpa: Vec<String>,
#[argh(option, long = "vsock")] #[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>, vsock: Option<String>,
#[argh(option, long = "numa")] #[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>, numa: Vec<String>,
#[argh(switch, long = "watchdog")] #[argh(switch, long = "watchdog")]
@@ -245,27 +235,12 @@ pub struct TopLevel {
/// path=<path/to/a/file>|fd=<fd> /// path=<path/to/a/file>|fd=<fd>
api_socket: Option<String>, 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")] #[argh(option, long = "event-monitor")]
/// path=<path/to/a/file>|fd=<fd> /// path=<path/to/a/file>|fd=<fd>
event_monitor: Option<String>, event_monitor: Option<String>,
#[argh(option, long = "restore")] #[argh(option, long = "restore")]
/// source_url=<source_url>, prefault=on|off /// source_url=<source_url>,prefault=on|off
restore: Option<String>, restore: Option<String>,
#[argh(option, long = "seccomp", default = "String::from(\"true\")")] #[argh(option, long = "seccomp", default = "String::from(\"true\")")]
@@ -278,7 +253,7 @@ pub struct TopLevel {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
#[argh(option, long = "sgx-epc")] #[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>, sgx_epc: Vec<String>,
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
@@ -439,18 +414,6 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
(None, None) (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 { if let Some(ref monitor_config) = toplevel.event_monitor {
let mut parser = OptionParser::new(); let mut parser = OptionParser::new();
parser.add("path").add("fd"); parser.add("path").add("fd");
@@ -480,7 +443,7 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
let (api_request_sender, api_request_receiver) = channel(); let (api_request_sender, api_request_receiver) = channel();
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?; 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 { let seccomp_action = match &toplevel.seccomp as &str {
"true" => SeccompAction::Trap, "true" => SeccompAction::Trap,
"false" => SeccompAction::Allow, "false" => SeccompAction::Allow,
@@ -546,16 +509,12 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?; let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?; let vmm_thread = vmm::start_vmm_thread(
env!("CARGO_PKG_VERSION").to_string(),
let vmm_thread_handle = vmm::start_vmm_thread(
vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
&api_socket_path, &api_socket_path,
api_socket_fd, api_socket_fd,
#[cfg(feature = "dbus_api")]
dbus_options,
api_evt.try_clone().unwrap(), api_evt.try_clone().unwrap(),
api_request_sender_clone, http_sender,
api_request_receiver, api_request_receiver,
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
gdb_socket_path, gdb_socket_path,
@@ -563,60 +522,41 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
debug_evt.try_clone().unwrap(), debug_evt.try_clone().unwrap(),
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
vm_debug_evt.try_clone().unwrap(), vm_debug_evt.try_clone().unwrap(),
exit_evt.try_clone().unwrap(),
&seccomp_action, &seccomp_action,
hypervisor, hypervisor,
) )
.map_err(Error::StartVmmThread)?; .map_err(Error::StartVmmThread)?;
let r: Result<(), Error> = (|| { let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
if payload_present { if payload_present {
let vm_params = toplevel.to_vm_params(); let vm_params = toplevel.to_vm_params();
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?; let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
// Create and boot the VM based off the VM config we just built. // Create and boot the VM based off the VM config we just built.
let sender = api_request_sender.clone(); let sender = api_request_sender.clone();
vmm::api::vm_create( vmm::api::vm_create(
api_evt.try_clone().unwrap(), api_evt.try_clone().unwrap(),
api_request_sender, api_request_sender,
Arc::new(Mutex::new(vm_config)), Arc::new(Mutex::new(vm_config)),
) )
.map_err(Error::VmCreate)?; .map_err(Error::VmCreate)?;
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?; vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
} else if let Some(restore_params) = toplevel.restore { } else if let Some(restore_params) = toplevel.restore {
vmm::api::vm_restore( vmm::api::vm_restore(
api_evt.try_clone().unwrap(), api_evt.try_clone().unwrap(),
api_request_sender, api_request_sender,
Arc::new( Arc::new(config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?),
config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?, )
), .map_err(Error::VmRestore)?;
)
.map_err(Error::VmRestore)?;
}
Ok(())
})();
if r.is_err() {
if let Err(e) = exit_evt.write(1) {
warn!("writing to exit EventFd: {e}");
}
} }
vmm_thread_handle vmm_thread
.thread_handle
.join() .join()
.map_err(Error::ThreadJoin)? .map_err(Error::ThreadJoin)?
.map_err(Error::VmmThread)?; .map_err(Error::VmmThread)?;
#[cfg(feature = "dbus_api")] Ok(api_socket_path)
if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
dbus_api_graceful_shutdown(chs);
}
r.map(|_| api_socket_path)
} }
fn main() { fn main() {
@@ -630,7 +570,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env(); let toplevel: TopLevel = argh::from_env();
if toplevel.version { if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return; return;
} }

View File

@@ -1,2 +0,0 @@
instance-id: cloud
local-hostname: cloud

View File

@@ -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

View File

@@ -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

View File

@@ -5,12 +5,12 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
dirs = "5.0.0" dirs = "4.0.0"
epoll = "4.3.1" epoll = "4.3.1"
libc = "0.2.139" libc = "0.2.139"
once_cell = "1.17.1" once_cell = "1.17.1"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -249,8 +249,7 @@ impl DiskConfig for UbuntuDiskConfig {
.unwrap() .unwrap()
.join("test_data") .join("test_data")
.join("cloud-init") .join("cloud-init")
.join("ubuntu") .join("ubuntu");
.join("ci");
vec!["meta-data"].iter().for_each(|x| { vec!["meta-data"].iter().for_each(|x| {
rate_limited_copy(source_file_dir.join(x), cloud_init_directory.join(x)) rate_limited_copy(source_file_dir.join(x), cloud_init_directory.join(x))
@@ -869,6 +868,14 @@ impl Guest {
.map_err(Error::Parsing) .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> { pub fn get_total_memory(&self) -> Result<u32, Error> {
self.ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")? self.ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")?
.trim() .trim()
@@ -1345,7 +1352,6 @@ pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Resu
}) })
} }
#[derive(Clone)]
pub enum FioOps { pub enum FioOps {
Read, Read,
RandomRead, RandomRead,

View File

@@ -30,9 +30,6 @@ use test_infra::*;
use vmm_sys_util::{tempdir::TempDir, tempfile::TempFile}; use vmm_sys_util::{tempdir::TempDir, tempfile::TempFile};
use wait_timeout::ChildExt; use wait_timeout::ChildExt;
// Constant taken from the VMM crate.
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
mod x86_64 { mod x86_64 {
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw"; pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
@@ -73,324 +70,6 @@ const DIRECT_KERNEL_BOOT_CMDLINE: &str =
const CONSOLE_TEST_STRING: &str = "Started OpenBSD Secure Shell server"; 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) { fn prepare_virtiofsd(tmp_dir: &TempDir, shared_dir: &str) -> (std::process::Child, String) {
let mut workload_path = dirs::home_dir().unwrap(); let mut workload_path = dirs::home_dir().unwrap();
workload_path.push("workloads"); workload_path.push("workloads");
@@ -573,6 +252,26 @@ fn prepare_swtpm_daemon(tmp_dir: &TempDir) -> (std::process::Command, String) {
(swtpm_command, swtpm_socket_path) (swtpm_command, swtpm_socket_path)
} }
fn curl_command(api_socket: &str, method: &str, url: &str, http_body: Option<&str>) {
let mut curl_args: Vec<&str> = ["--unix-socket", api_socket, "-i", "-X", method, url].to_vec();
if let Some(body) = http_body {
curl_args.push("-H");
curl_args.push("Accept: application/json");
curl_args.push("-H");
curl_args.push("Content-Type: application/json");
curl_args.push("-d");
curl_args.push(body);
}
let status = Command::new("curl")
.args(curl_args)
.status()
.expect("Failed to launch curl command");
assert!(status.success());
}
fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool { fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
let mut cmd = Command::new(clh_command("ch-remote")); let mut cmd = Command::new(clh_command("ch-remote"));
cmd.args(["--api-socket", api_socket, command]); cmd.args(["--api-socket", api_socket, command]);
@@ -1525,10 +1224,7 @@ fn _test_virtio_fs(
.default_net() .default_net()
.args(["--api-socket", &api_socket]); .args(["--api-socket", &api_socket]);
if pci_segment.is_some() { if pci_segment.is_some() {
guest_command.args([ guest_command.args(["--platform", "num_pci_segments=16"]);
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
} }
let fs_params = format!( let fs_params = format!(
@@ -2264,6 +1960,7 @@ mod common_parallel {
guest.wait_vm_boot(Some(120)).unwrap(); guest.wait_vm_boot(Some(120)).unwrap();
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1); 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!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000"); assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
@@ -2367,16 +2064,19 @@ mod common_parallel {
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_421() { fn test_cpu_topology_421() {
test_cpu_topology(4, 2, 1, false); test_cpu_topology(4, 2, 1, false);
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_142() { fn test_cpu_topology_142() {
test_cpu_topology(1, 4, 2, false); test_cpu_topology(1, 4, 2, false);
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))]
fn test_cpu_topology_262() { fn test_cpu_topology_262() {
test_cpu_topology(2, 6, 2, false); test_cpu_topology(2, 6, 2, false);
} }
@@ -2548,7 +2248,7 @@ mod common_parallel {
"--memory-zone", "--memory-zone",
"id=mem0,size=1G,hotplug_size=2G", "id=mem0,size=1G,hotplug_size=2G",
"--memory-zone", "--memory-zone",
"id=mem1,size=1G,shared=on", "id=mem1,size=1G,file=/dev/shm",
"--memory-zone", "--memory-zone",
"id=mem2,size=1G,host_numa_node=0,hotplug_size=2G", "id=mem2,size=1G,host_numa_node=0,hotplug_size=2G",
]) ])
@@ -2637,10 +2337,7 @@ mod common_parallel {
.args(["--memory", "size=512M"]) .args(["--memory", "size=512M"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()]) .args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE]) .args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.args([ .args(["--platform", "num_pci_segments=16,iommu_segments=[1]"])
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS},iommu_segments=[1]"),
])
.default_disks() .default_disks()
.capture_output() .capture_output()
.default_net(); .default_net();
@@ -2796,10 +2493,7 @@ mod common_parallel {
.args(["--memory", "size=512M"]) .args(["--memory", "size=512M"])
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()]) .args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE]) .args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.args([ .args(["--platform", "num_pci_segments=16"])
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
])
.args([ .args([
"--disk", "--disk",
format!( format!(
@@ -2826,15 +2520,15 @@ mod common_parallel {
let grep_cmd = "lspci | grep \"Host bridge\" | wc -l"; let grep_cmd = "lspci | grep \"Host bridge\" | wc -l";
let r = std::panic::catch_unwind(|| { 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!( assert_eq!(
guest guest
.ssh_command(grep_cmd) .ssh_command(grep_cmd)
.unwrap() .unwrap()
.trim() .trim()
.parse::<u16>() .parse::<u32>()
.unwrap_or_default(), .unwrap_or_default(),
MAX_NUM_PCI_SEGMENTS 16
); );
// Check both if /dev/vdc exists and if the block size is 4M. // Check both if /dev/vdc exists and if the block size is 4M.
@@ -4050,7 +3744,7 @@ mod common_parallel {
// line (We tag the command line from cloud-hypervisor for that purpose). // line (We tag the command line from cloud-hypervisor for that purpose).
// The third device is added to validate that hotplug works correctly since // The third device is added to validate that hotplug works correctly since
// it is being added to the L2 VM through hotplugging mechanism. // it is being added to the L2 VM through hotplugging mechanism.
// Also, we pass-through a virtio-blk device to the L2 VM to test the 32-bit // Also, we pass-through a vitio-blk device to the L2 VM to test the 32-bit
// vfio device support // vfio device support
fn test_vfio() { fn test_vfio() {
setup_vfio_network_interfaces(); setup_vfio_network_interfaces();
@@ -4295,7 +3989,7 @@ mod common_parallel {
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket /tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
resize --memory 1073741824", resize --memory=1073741824",
) )
.unwrap(); .unwrap();
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000); assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);
@@ -4354,35 +4048,299 @@ mod common_parallel {
} }
#[test] #[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 focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal)); 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));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// 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] #[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 focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal)); 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));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// 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(|| {
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.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
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.shutdown",
None,
);
// Then boot it again
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.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] #[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 focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal)); 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));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// 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(|| {
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.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
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.delete",
None,
);
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it again
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.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] #[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 focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal)); 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));
// Verify API server is running
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
// 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,
);
curl_command(
&api_socket,
"PUT",
"http://localhost/api/v1/vm.create",
Some(&http_body),
);
// Then boot it
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.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!(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] #[test]
@@ -4996,6 +4954,7 @@ mod common_parallel {
handle_child_output(r, &output); handle_child_output(r, &output);
} }
#[allow(clippy::useless_conversion)]
fn create_loop_device(backing_file_path: &str, block_size: u32, num_retries: usize) -> String { fn create_loop_device(backing_file_path: &str, block_size: u32, num_retries: usize) -> String {
const LOOP_CONFIGURE: u64 = 0x4c0a; const LOOP_CONFIGURE: u64 = 0x4c0a;
const LOOP_CTL_GET_FREE: u64 = 0x4c82; const LOOP_CTL_GET_FREE: u64 = 0x4c82;
@@ -5056,9 +5015,12 @@ mod common_parallel {
.unwrap(); .unwrap();
// Request a free loop device // Request a free loop device
let loop_device_number = let loop_device_number = unsafe {
unsafe { libc::ioctl(loop_ctl_file.as_raw_fd(), LOOP_CTL_GET_FREE as _) }; libc::ioctl(
loop_ctl_file.as_raw_fd(),
LOOP_CTL_GET_FREE.try_into().unwrap(),
)
};
if loop_device_number < 0 { if loop_device_number < 0 {
panic!("Couldn't find a free loop device"); panic!("Couldn't find a free loop device");
} }
@@ -5090,7 +5052,7 @@ mod common_parallel {
let ret = unsafe { let ret = unsafe {
libc::ioctl( libc::ioctl(
loop_device_file.as_raw_fd(), loop_device_file.as_raw_fd(),
LOOP_CONFIGURE as _, LOOP_CONFIGURE.try_into().unwrap(),
&loop_config, &loop_config,
) )
}; };
@@ -5275,7 +5237,6 @@ mod common_parallel {
} }
#[test] #[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_balloon_free_page_reporting() { fn test_virtio_balloon_free_page_reporting() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string()); let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal)); let guest = Guest::new(Box::new(focal));
@@ -5375,10 +5336,7 @@ mod common_parallel {
.capture_output(); .capture_output();
if pci_segment.is_some() { if pci_segment.is_some() {
cmd.args([ cmd.args(["--platform", "num_pci_segments=16"]);
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
} }
let mut child = cmd.spawn().unwrap(); let mut child = cmd.spawn().unwrap();
@@ -5514,10 +5472,7 @@ mod common_parallel {
.capture_output(); .capture_output();
if pci_segment.is_some() { if pci_segment.is_some() {
cmd.args([ cmd.args(["--platform", "num_pci_segments=16"]);
"--platform",
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
]);
} }
let mut child = cmd.spawn().unwrap(); let mut child = cmd.spawn().unwrap();
@@ -6345,13 +6300,11 @@ mod common_parallel {
} }
#[test] #[test]
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
fn test_macvtap() { fn test_macvtap() {
_test_macvtap(false, "guestmacvtap0", "hostmacvtap0") _test_macvtap(false, "guestmacvtap0", "hostmacvtap0")
} }
#[test] #[test]
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
fn test_macvtap_hotplug() { fn test_macvtap_hotplug() {
_test_macvtap(true, "guestmacvtap1", "hostmacvtap1") _test_macvtap(true, "guestmacvtap1", "hostmacvtap1")
} }
@@ -6861,116 +6814,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 { mod common_sequential {
#[cfg(not(feature = "mshv"))] #[cfg(not(feature = "mshv"))]
use crate::*; use crate::*;
@@ -8282,7 +8125,7 @@ mod vfio {
.ssh_command_l1( .ssh_command_l1(
"sudo /mnt/ch-remote \ "sudo /mnt/ch-remote \
--api-socket /tmp/ch_api.sock \ --api-socket /tmp/ch_api.sock \
resize --memory 1073741824", resize --memory=1073741824",
) )
.unwrap(); .unwrap();
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000); assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);

View File

@@ -309,7 +309,11 @@ impl Emulator {
} }
self.established_flag_cached = true; self.established_flag_cached = true;
self.established_flag = est.resp.bit == 0; if est.resp.bit != 0 {
self.established_flag = false;
} else {
self.established_flag = true;
}
self.established_flag self.established_flag
} }

View File

@@ -8,8 +8,8 @@ edition = "2021"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
once_cell = "1.17.1" once_cell = "1.17.1"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"
[features] [features]
tracing = [] tracing = []

View File

@@ -11,5 +11,5 @@ crc32c = "0.6.3"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
remain = "0.2.6" remain = "0.2.6"
thiserror = "1.0.40" thiserror = "1.0.38"
uuid = { version = "1.3.4", features = ["v4"] } uuid = { version = "1.3.0", features = ["v4"] }

View File

@@ -145,7 +145,11 @@ impl DiskSpec {
let bits = f let bits = f
.read_u32::<LittleEndian>() .read_u32::<LittleEndian>()
.map_err(VhdxMetadataError::ReadMetadata)?; .map_err(VhdxMetadataError::ReadMetadata)?;
disk_spec.has_parent = bits & BLOCK_HAS_PARENT != 0; if bits & BLOCK_HAS_PARENT != 0 {
disk_spec.has_parent = true;
} else {
disk_spec.has_parent = false;
}
metadata_presence |= METADATA_FILE_PARAMETER_PRESENT; metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
} else if metadata_entry.item_id } else if metadata_entry.item_id

View File

@@ -14,10 +14,10 @@ libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
option_parser = { path = "../option_parser" } option_parser = { path = "../option_parser" }
qcow = { path = "../qcow" } qcow = { path = "../qcow" }
vhost = { version = "0.7.0", features = ["vhost-user-slave"] } vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
vhost-user-backend = "0.9.0" vhost-user-backend = "0.8.0"
virtio-bindings = "0.2.0" virtio-bindings = "0.2.0"
virtio-queue = "0.8.0" virtio-queue = "0.7.0"
vm-memory = "0.11.0" vm-memory = "0.10.0"
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"

View File

@@ -32,7 +32,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env(); let toplevel: TopLevel = argh::from_env();
if toplevel.version { if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return; return;
} }

View File

@@ -13,9 +13,9 @@ libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
net_util = { path = "../net_util" } net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" } option_parser = { path = "../option_parser" }
vhost = { version = "0.7.0", features = ["vhost-user-slave"] } vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
vhost-user-backend = "0.9.0" vhost-user-backend = "0.8.0"
virtio-bindings = "0.2.0" virtio-bindings = "0.2.0"
vm-memory = "0.11.0" vm-memory = "0.10.0"
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"

View File

@@ -28,7 +28,7 @@ fn main() {
let toplevel: TopLevel = argh::from_env(); let toplevel: TopLevel = argh::from_env();
if toplevel.version { if toplevel.version {
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION")); println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
return; return;
} }

View File

@@ -8,13 +8,13 @@ edition = "2021"
default = [] default = []
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
arc-swap = "1.5.1" arc-swap = "1.5.1"
block_util = { path = "../block_util" } block_util = { path = "../block_util" }
byteorder = "1.4.3" byteorder = "1.4.3"
epoll = "4.3.1" epoll = "4.3.1"
event_monitor = { path = "../event_monitor" } event_monitor = { path = "../event_monitor" }
io-uring = "0.5.13" io-uring = "0.5.12"
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
net_gen = { path = "../net_gen" } net_gen = { path = "../net_gen" }
@@ -22,18 +22,18 @@ net_util = { path = "../net_util" }
pci = { path = "../pci" } pci = { path = "../pci" }
rate_limiter = { path = "../rate_limiter" } rate_limiter = { path = "../rate_limiter" }
seccompiler = "0.3.0" seccompiler = "0.3.0"
serde = { version = "1.0.164", features = ["derive"] } serde = { version = "1.0.151", features = ["derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"
serial_buffer = { path = "../serial_buffer" } serial_buffer = { path = "../serial_buffer" }
thiserror = "1.0.40" thiserror = "1.0.38"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" 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-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.8.0" virtio-queue = "0.7.0"
vm-allocator = { path = "../vm-allocator" } vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" } 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-migration = { path = "../vm-migration" }
vm-virtio = { path = "../vm-virtio" } vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0" vmm-sys-util = "0.11.0"

View File

@@ -39,24 +39,19 @@ pub mod vhost_user;
pub mod vsock; pub mod vsock;
pub mod watchdog; pub mod watchdog;
pub use self::balloon::Balloon; pub use self::balloon::*;
pub use self::block::{Block, BlockState}; pub use self::block::*;
pub use self::console::{Console, ConsoleResizer, Endpoint}; pub use self::console::*;
pub use self::device::{ pub use self::device::*;
DmaRemapping, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioInterrupt, pub use self::epoll_helper::*;
VirtioInterruptType, VirtioSharedMemoryList, pub use self::iommu::*;
}; pub use self::mem::*;
pub use self::epoll_helper::{ pub use self::net::*;
EpollHelper, EpollHelperError, EpollHelperHandler, EPOLL_HELPER_EVENT_LAST, pub use self::pmem::*;
}; pub use self::rng::*;
pub use self::iommu::{AccessPlatformMapping, Iommu, IommuMapping}; pub use self::vdpa::*;
pub use self::mem::{BlocksState, Mem, VirtioMemMappingSource, VIRTIO_MEM_ALIGN_SIZE}; pub use self::vsock::*;
pub use self::net::{Net, NetCtrlEpollHandler}; pub use self::watchdog::*;
pub use self::pmem::Pmem;
pub use self::rng::Rng;
pub use self::vdpa::{Vdpa, VdpaDmaMapping};
pub use self::vsock::Vsock;
pub use self::watchdog::Watchdog;
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory}; use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory};
use vm_virtio::VirtioDeviceType; use vm_virtio::VirtioDeviceType;
@@ -91,8 +86,8 @@ pub enum ActivateError {
ThreadSpawn(std::io::Error), ThreadSpawn(std::io::Error),
#[error("Failed to setup vhost-user-fs daemon: {0}")] #[error("Failed to setup vhost-user-fs daemon: {0}")]
VhostUserFsSetup(vhost_user::Error), VhostUserFsSetup(vhost_user::Error),
#[error("Failed to setup vhost-user daemon: {0}")] #[error("Failed to setup vhost-user-blk daemon: {0}")]
VhostUserSetup(vhost_user::Error), VhostUserBlkSetup(vhost_user::Error),
#[error("Failed to create seccomp filter: {0}")] #[error("Failed to create seccomp filter: {0}")]
CreateSeccompFilter(seccompiler::Error), CreateSeccompFilter(seccompiler::Error),
#[error("Failed to create rate limiter: {0}")] #[error("Failed to create rate limiter: {0}")]

View File

@@ -259,7 +259,6 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
(libc::SYS_madvise, vec![]), (libc::SYS_madvise, vec![]),
(libc::SYS_mmap, vec![]), (libc::SYS_mmap, vec![]),
(libc::SYS_mprotect, vec![]), (libc::SYS_mprotect, vec![]),
(libc::SYS_mremap, vec![]),
(libc::SYS_munmap, vec![]), (libc::SYS_munmap, vec![]),
(libc::SYS_openat, vec![]), (libc::SYS_openat, vec![]),
(libc::SYS_read, vec![]), (libc::SYS_read, vec![]),

View File

@@ -48,13 +48,14 @@ use super::pci_common_config::VirtioPciCommonConfigState;
/// Vector value used to disable MSI for a queue. /// Vector value used to disable MSI for a queue.
const VIRTQ_MSI_NO_VECTOR: u16 = 0xffff; const VIRTQ_MSI_NO_VECTOR: u16 = 0xffff;
#[allow(clippy::enum_variant_names)]
enum PciCapabilityType { enum PciCapabilityType {
Common = 1, CommonConfig = 1,
Notify = 2, NotifyConfig = 2,
Isr = 3, IsrConfig = 3,
Device = 4, DeviceConfig = 4,
Pci = 5, PciConfig = 5,
SharedMemory = 8, SharedMemoryConfig = 8,
} }
// This offset represents the 2 bytes omitted from the VirtioPciCap structure // This offset represents the 2 bytes omitted from the VirtioPciCap structure
@@ -209,7 +210,7 @@ impl PciCapability for VirtioPciCfgCap {
impl VirtioPciCfgCap { impl VirtioPciCfgCap {
fn new() -> Self { fn new() -> Self {
VirtioPciCfgCap { VirtioPciCfgCap {
cap: VirtioPciCap::new(PciCapabilityType::Pci, 0, 0, 0), cap: VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0),
..Default::default() ..Default::default()
} }
} }
@@ -666,7 +667,7 @@ impl VirtioPciDevice {
) -> std::result::Result<(), PciDeviceError> { ) -> std::result::Result<(), PciDeviceError> {
// Add pointers to the different configuration structures from the PCI capabilities. // Add pointers to the different configuration structures from the PCI capabilities.
let common_cap = VirtioPciCap::new( let common_cap = VirtioPciCap::new(
PciCapabilityType::Common, PciCapabilityType::CommonConfig,
settings_bar, settings_bar,
COMMON_CONFIG_BAR_OFFSET as u32, COMMON_CONFIG_BAR_OFFSET as u32,
COMMON_CONFIG_SIZE as u32, COMMON_CONFIG_SIZE as u32,
@@ -676,7 +677,7 @@ impl VirtioPciDevice {
.map_err(PciDeviceError::CapabilitiesSetup)?; .map_err(PciDeviceError::CapabilitiesSetup)?;
let isr_cap = VirtioPciCap::new( let isr_cap = VirtioPciCap::new(
PciCapabilityType::Isr, PciCapabilityType::IsrConfig,
settings_bar, settings_bar,
ISR_CONFIG_BAR_OFFSET as u32, ISR_CONFIG_BAR_OFFSET as u32,
ISR_CONFIG_SIZE as u32, ISR_CONFIG_SIZE as u32,
@@ -687,7 +688,7 @@ impl VirtioPciDevice {
// TODO(dgreid) - set based on device's configuration size? // TODO(dgreid) - set based on device's configuration size?
let device_cap = VirtioPciCap::new( let device_cap = VirtioPciCap::new(
PciCapabilityType::Device, PciCapabilityType::DeviceConfig,
settings_bar, settings_bar,
DEVICE_CONFIG_BAR_OFFSET as u32, DEVICE_CONFIG_BAR_OFFSET as u32,
DEVICE_CONFIG_SIZE as u32, DEVICE_CONFIG_SIZE as u32,
@@ -697,7 +698,7 @@ impl VirtioPciDevice {
.map_err(PciDeviceError::CapabilitiesSetup)?; .map_err(PciDeviceError::CapabilitiesSetup)?;
let notify_cap = VirtioPciNotifyCap::new( let notify_cap = VirtioPciNotifyCap::new(
PciCapabilityType::Notify, PciCapabilityType::NotifyConfig,
settings_bar, settings_bar,
NOTIFICATION_BAR_OFFSET as u32, NOTIFICATION_BAR_OFFSET as u32,
NOTIFICATION_SIZE as u32, NOTIFICATION_SIZE as u32,
@@ -1056,7 +1057,7 @@ impl PciDevice for VirtioPciDevice {
for (idx, shm) in shm_list.region_list.iter().enumerate() { for (idx, shm) in shm_list.region_list.iter().enumerate() {
let shm_cap = VirtioPciCap64::new( let shm_cap = VirtioPciCap64::new(
PciCapabilityType::SharedMemory, PciCapabilityType::SharedMemoryConfig,
VIRTIO_SHM_BAR_INDEX as u8, VIRTIO_SHM_BAR_INDEX as u8,
idx as u8, idx as u8,
shm.offset, shm.offset,

View File

@@ -605,7 +605,7 @@ impl VirtioDevice for Fs {
&mut self, &mut self,
shm_regions: VirtioSharedMemoryList, shm_regions: VirtioSharedMemoryList,
) -> std::result::Result<(), crate::Error> { ) -> std::result::Result<(), crate::Error> {
if let Some(cache) = self.cache.as_mut() { if let Some(mut cache) = self.cache.as_mut() {
cache.0 = shm_regions; cache.0 = shm_regions;
Ok(()) Ok(())
} else { } else {

View File

@@ -237,7 +237,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
.map_err(|e| { .map_err(|e| {
EpollHelperError::IoError(std::io::Error::new( EpollHelperError::IoError(std::io::Error::new(
std::io::ErrorKind::Other, 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, &slave_req_handler,
inflight.as_mut(), inflight.as_mut(),
) )
.map_err(ActivateError::VhostUserSetup)?; .map_err(ActivateError::VhostUserBlkSetup)?;
Ok(VhostUserEpollHandler { Ok(VhostUserEpollHandler {
vu: vu.clone(), vu: vu.clone(),
@@ -413,7 +413,7 @@ impl VhostUserCommon {
pub fn pause(&mut self) -> std::result::Result<(), MigratableError> { pub fn pause(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vu) = &self.vu { if let Some(vu) = &self.vu {
vu.lock().unwrap().pause_vhost_user().map_err(|e| { 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 { } else {
Ok(()) Ok(())
@@ -423,7 +423,7 @@ impl VhostUserCommon {
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> { pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
if let Some(vu) = &self.vu { if let Some(vu) = &self.vu {
vu.lock().unwrap().resume_vhost_user().map_err(|e| { 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 { } else {
Ok(()) Ok(())

View File

@@ -1,28 +1,28 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! The main job of `VsockConnection` is to forward data traffic, back and forth, between a /// The main job of `VsockConnection` is to forward data traffic, back and forth, between a
//! guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while /// guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while
//! also managing its internal state. /// also managing its internal state.
//! To that end, `VsockConnection` implements: /// To that end, `VsockConnection` implements:
//! - `VsockChannel` for: /// - `VsockChannel` for:
//! - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and /// - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and
//! - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and /// - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and
//! - updating its internal state, by absorbing control packets (anything other than /// - updating its internal state, by absorbing control packets (anything other than
//! VSOCK_OP_RW). /// VSOCK_OP_RW).
//! - `VsockEpollListener` for getting notified about the availability of data or free buffer /// - `VsockEpollListener` for getting notified about the availability of data or free buffer
//! space at the host stream. /// space at the host stream.
//! ///
//! Note: there is a certain asymmetry to the RX and TX data flows: /// Note: there is a certain asymmetry to the RX and TX data flows:
//! - RX transfers do not need any data buffering, since data is read straight from the /// - RX transfers do not need any data buffering, since data is read straight from the
//! host stream and into the guest-provided RX buffer; /// host stream and into the guest-provided RX buffer;
//! - TX transfers may require some data to be buffered by `VsockConnection`, if the host /// - TX transfers may require some data to be buffered by `VsockConnection`, if the host
//! peer can't keep up with reading the data that we're writing. This is because, once /// peer can't keep up with reading the data that we're writing. This is because, once
//! the guest driver provides some data in a virtio TX buffer, the vsock device must /// the guest driver provides some data in a virtio TX buffer, the vsock device must
//! consume it. If that data can't be forwarded straight to the host stream, we'll /// consume it. If that data can't be forwarded straight to the host stream, we'll
//! have to store it in a buffer (and flush it at a later time). Vsock flow control /// have to store it in a buffer (and flush it at a later time). Vsock flow control
//! ensures that our TX buffer doesn't overflow. /// ensures that our TX buffer doesn't overflow.
// ///
// The code in this file is best read with a fresh memory of the vsock protocol inner-workings. // The code in this file is best read with a fresh memory of the vsock protocol inner-workings.
// To help with that, here is a // To help with that, here is a
// //

View File

@@ -1,9 +1,9 @@
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! This module implements our vsock connection state machine. The heavy lifting is done by /// This module implements our vsock connection state machine. The heavy lifting is done by
//! `connection::VsockConnection`, while this file only defines some constants and helper structs. /// `connection::VsockConnection`, while this file only defines some constants and helper structs.
///
mod connection; mod connection;
mod txbuf; mod txbuf;

View File

@@ -2,19 +2,19 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues. /// `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues.
//! There are two components to a vsock packet, each using its own descriptor in a /// There are two components to a vsock packet, each using its own descriptor in a
//! virtio queue: /// virtio queue:
//! - the packet header; and /// - the packet header; and
//! - the packet data/buffer. /// - the packet data/buffer.
//! There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds /// There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds
//! the header, and an optional second descriptor holds the data. The second descriptor is only /// the header, and an optional second descriptor holds the data. The second descriptor is only
//! present for data packets (VSOCK_OP_RW). /// present for data packets (VSOCK_OP_RW).
//! ///
//! `VsockPacket` wraps these two buffers and provides direct access to the data stored /// `VsockPacket` wraps these two buffers and provides direct access to the data stored
//! in guest memory. This is done to avoid unnecessarily copying data from guest memory /// in guest memory. This is done to avoid unnecessarily copying data from guest memory
//! to temporary buffers, before passing it on to the vsock backend. /// to temporary buffers, before passing it on to the vsock backend.
///
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; use std::sync::Arc;
@@ -436,6 +436,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_tx_packet_assembly() { fn test_tx_packet_assembly() {
// Test case: successful TX packet assembly. // Test case: successful TX packet assembly.
{ {
@@ -580,6 +581,7 @@ mod tests {
} }
#[test] #[test]
#[allow(clippy::cognitive_complexity)]
fn test_packet_hdr_accessors() { fn test_packet_hdr_accessors() {
const SRC_CID: u64 = 1; const SRC_CID: u64 = 1;
const DST_CID: u64 = 2; const DST_CID: u64 = 2;

View File

@@ -2,13 +2,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! This module implements the Unix Domain Sockets backend for vsock - a mediator between /// This module implements the Unix Domain Sockets backend for vsock - a mediator between
//! guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by /// guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by
//! `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for /// `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for
//! handling vsock connection states. /// handling vsock connection states.
//! /// Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend.
//! Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend. ///
mod muxer; mod muxer;
mod muxer_killq; mod muxer_killq;
mod muxer_rxq; mod muxer_rxq;

View File

@@ -2,42 +2,35 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e. /// `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e.
//! by implementing the `VsockBackend` trait, it abstracts away the gory details of translating /// by implementing the `VsockBackend` trait, it abstracts away the gory details of translating
//! between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock /// between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock
//! device model. /// device model.
//! ///
//! The vsock muxer has two main roles: /// The vsock muxer has two main roles:
//! /// 1. Vsock connection multiplexer:
//! ## Vsock connection multiplexer /// It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The
//! /// muxer also routes packets to their owning connections. It does so via a connection
//! It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The /// `HashMap`, keyed by what is basically a (host_port, guest_port) tuple.
//! muxer also routes packets to their owning connections. It does so via a connection /// Vsock packet traffic needs to be inspected, in order to detect connection request
//! `HashMap`, keyed by what is basically a (host_port, guest_port) tuple. /// packets (leading to the creation of a new connection), and connection reset packets
//! /// (leading to the termination of an existing connection). All other packets, though, must
//! Vsock packet traffic needs to be inspected, in order to detect connection request /// belong to an existing connection and, as such, the muxer simply forwards them.
//! packets (leading to the creation of a new connection), and connection reset packets /// 2. Event dispatcher
//! (leading to the termination of an existing connection). All other packets, though, must /// There are three event categories that the vsock backend is interested it:
//! belong to an existing connection and, as such, the muxer simply forwards them. /// 1. A new host-initiated connection is ready to be accepted from the listening host Unix
//! /// socket;
//! ## Event dispatcher /// 2. Data is available for reading from a newly-accepted host-initiated connection (i.e.
//! /// the host is ready to issue a vsock connection request, informing us of the
//! There are three event categories that the vsock backend is interested it: /// destination port to which it wants to connect);
//! 1. A new host-initiated connection is ready to be accepted from the listening host Unix /// 3. Some event was triggered for a connected Unix socket, that belongs to a
//! socket; /// `VsockConnection`.
//! 2. Data is available for reading from a newly-accepted host-initiated connection (i.e. /// The muxer gets notified about all of these events, because, as a `VsockEpollListener`
//! the host is ready to issue a vsock connection request, informing us of the /// implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
//! destination port to which it wants to connect); /// other pollable FDs are then registered under this nested epoll FD.
//! 3. Some event was triggered for a connected Unix socket, that belongs to a /// To route all these events to their handlers, the muxer uses another `HashMap` object,
//! `VsockConnection`. /// mapping `RawFd`s to `EpollListener`s.
//! ///
//! The muxer gets notified about all of these events, because, as a `VsockEpollListener`
//! implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
//! other pollable FDs are then registered under this nested epoll FD.
//!
//! To route all these events to their handlers, the muxer uses another `HashMap` object,
//! mapping `RawFd`s to `EpollListener`s.
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
use std::io::{self, Read}; use std::io::{self, Read};
@@ -87,7 +80,7 @@ enum EpollListener {
}, },
/// A listener interested in new host-initiated connections. /// A listener interested in new host-initiated connections.
HostSock, HostSock,
/// A listener interested in reading host "connect \<port>" commands from a freshly /// A listener interested in reading host "connect <port>" commands from a freshly
/// connected host socket. /// connected host socket.
LocalStream(UnixStream), LocalStream(UnixStream),
} }
@@ -113,7 +106,7 @@ pub struct VsockMuxer {
/// The Unix socket, through which host-initiated connections are accepted. /// The Unix socket, through which host-initiated connections are accepted.
host_sock: UnixListener, host_sock: UnixListener,
/// The file system path of the host-side Unix socket. This is used to figure out the path /// The file system path of the host-side Unix socket. This is used to figure out the path
/// to Unix sockets listening on specific ports. I.e. "\<this path>_\<port number>". /// to Unix sockets listening on specific ports. I.e. "<this path>_<port number>".
host_sock_path: String, host_sock_path: String,
/// The nested epoll File, used to register epoll listeners. /// The nested epoll File, used to register epoll listeners.
epoll_file: File, epoll_file: File,

View File

@@ -2,29 +2,29 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced /// `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced
//! connection termination. I.e. after one peer issues a clean shutdown request /// connection termination. I.e. after one peer issues a clean shutdown request
//! (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in /// (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in
//! the near future (herein implemented via an expiring timer). /// the near future (herein implemented via an expiring timer).
//! ///
//! Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather /// Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather
//! an identifier - the connection key) to this queue. A subsequent pop() operation will /// an identifier - the connection key) to this queue. A subsequent pop() operation will
//! succeed if and only if the first connection in the queue is ready to be terminated (i.e. /// succeed if and only if the first connection in the queue is ready to be terminated (i.e.
//! its kill timer expired). /// its kill timer expired).
//! ///
//! Without using this queue, the muxer would have to walk its entire connection pool /// Without using this queue, the muxer would have to walk its entire connection pool
//! (hashmap), whenever it needs to check for expired kill timers. With this queue, both /// (hashmap), whenever it needs to check for expired kill timers. With this queue, both
//! scheduling and termination are performed in constant time. However, since we don't want to /// scheduling and termination are performed in constant time. However, since we don't want to
//! waste space on a kill queue that's as big as the connection hashmap itself, it is possible /// waste space on a kill queue that's as big as the connection hashmap itself, it is possible
//! that this queue may become full at times. We call this kill queue "synchronized" if we are /// that this queue may become full at times. We call this kill queue "synchronized" if we are
//! certain that all connections that are awaiting termination are present in the queue. This /// certain that all connections that are awaiting termination are present in the queue. This
//! means a simple constant-time pop() operation is enough to check whether any connections /// means a simple constant-time pop() operation is enough to check whether any connections
//! need to be terminated. When the kill queue becomes full, though, pushing fails, so /// need to be terminated. When the kill queue becomes full, though, pushing fails, so
//! connections that should be terminated are left out. The queue is not synchronized anymore. /// connections that should be terminated are left out. The queue is not synchronized anymore.
//! When that happens, the muxer will first drain the queue, and then replace it with a new /// When that happens, the muxer will first drain the queue, and then replace it with a new
//! queue, created by walking the connection pool, looking for connections that will be /// queue, created by walking the connection pool, looking for connections that will be
//! expiring in the future. /// expiring in the future.
///
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use std::time::Instant; use std::time::Instant;

View File

@@ -2,20 +2,20 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//! `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest) /// `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest)
//! packets (or rather instructions on how to build said packets). /// packets (or rather instructions on how to build said packets).
//! ///
//! Under ideal operation, every connection, that has pending RX data, will be present in the muxer /// Under ideal operation, every connection, that has pending RX data, will be present in the muxer
//! RX queue. However, since the RX queue is smaller than the connection pool, it may, under some /// RX queue. However, since the RX queue is smaller than the connection pool, it may, under some
//! conditions, become full, meaning that it can no longer account for all the connections that can /// conditions, become full, meaning that it can no longer account for all the connections that can
//! yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the /// yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the
//! connection pool). A desynchronized RX queue still holds valid data, and the muxer will /// connection pool). A desynchronized RX queue still holds valid data, and the muxer will
//! continue to pop packets from it. However, when a desynchronized queue is drained, additional /// continue to pop packets from it. However, when a desynchronized queue is drained, additional
//! data may still be available, so the muxer will have to perform a more costly walk of the entire /// data may still be available, so the muxer will have to perform a more costly walk of the entire
//! connection pool to find it. This walk is performed here, as part of building an RX queue from /// connection pool to find it. This walk is performed here, as part of building an RX queue from
//! the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to /// the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to
//! rebuild a synced one. /// rebuild a synced one.
///
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use super::super::VsockChannel; use super::super::VsockChannel;

View File

@@ -6,7 +6,7 @@ edition = "2021"
[dependencies] [dependencies]
libc = "0.2.139" libc = "0.2.139"
vm-memory = "0.11.0" vm-memory = "0.10.0"
[target.'cfg(target_arch = "aarch64")'.dependencies] [target.'cfg(target_arch = "aarch64")'.dependencies]
arch = { path = "../arch" } arch = { path = "../arch" }

View File

@@ -63,6 +63,7 @@ impl GsiAllocator {
} }
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[allow(clippy::new_without_default)]
/// New GSI allocator /// New GSI allocator
pub fn new() -> Self { pub fn new() -> Self {
GsiAllocator { GsiAllocator {
@@ -105,10 +106,3 @@ impl GsiAllocator {
Ok(irq) Ok(irq)
} }
} }
#[cfg(target_arch = "aarch64")]
impl Default for GsiAllocator {
fn default() -> Self {
GsiAllocator::new()
}
}

View File

@@ -12,8 +12,6 @@
mod address; mod address;
mod gsi; mod gsi;
/// page size related utility funtions
pub mod page_size;
mod system; mod system;
pub use crate::address::AddressAllocator; pub use crate::address::AddressAllocator;

View File

@@ -1,38 +0,0 @@
// Copyright 2023 Arm Limited (or its affiliates). All rights reserved.
// SPDX-License-Identifier: Apache-2.0
use libc::{sysconf, _SC_PAGESIZE};
/// get host page size
pub fn get_page_size() -> u64 {
// SAFETY: FFI call. Trivially safe.
unsafe { sysconf(_SC_PAGESIZE) as u64 }
}
/// round up address to let it align page size
pub fn align_page_size_up(address: u64) -> u64 {
let page_size = get_page_size();
(address + page_size - 1) & !(page_size - 1)
}
/// round down address to let it align page size
pub fn align_page_size_down(address: u64) -> u64 {
let page_size = get_page_size();
address & !(page_size - 1)
}
/// Test if address is 4k aligned
pub fn is_4k_aligned(address: u64) -> bool {
(address & 0xfff) == 0
}
/// Test if size is 4k aligned
pub fn is_4k_multiple(size: u64) -> bool {
(size & 0xfff) == 0
}
/// Test if address is page size aligned
pub fn is_page_size_aligned(address: u64) -> bool {
let page_size = get_page_size();
address & (page_size - 1) == 0
}

View File

@@ -14,7 +14,14 @@ use crate::gsi::GsiAllocator;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::gsi::GsiApic; use crate::gsi::GsiApic;
use crate::page_size::get_page_size; use libc::{sysconf, _SC_PAGESIZE};
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
#[inline(always)]
fn pagesize() -> usize {
// SAFETY: FFI call. Trivially safe.
unsafe { sysconf(_SC_PAGESIZE) as usize }
}
/// Manages allocating system resources such as address space and interrupt numbers. /// Manages allocating system resources such as address space and interrupt numbers.
/// ///
@@ -119,7 +126,7 @@ impl SystemAllocator {
self.platform_mmio_address_space.allocate( self.platform_mmio_address_space.allocate(
address, address,
size, size,
Some(align_size.unwrap_or(get_page_size())), Some(align_size.unwrap_or(pagesize() as u64)),
) )
} }
@@ -133,7 +140,7 @@ impl SystemAllocator {
self.mmio_hole_address_space.allocate( self.mmio_hole_address_space.allocate(
address, address,
size, size,
Some(align_size.unwrap_or(get_page_size())), Some(align_size.unwrap_or(pagesize() as u64)),
) )
} }

View File

@@ -10,11 +10,11 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"] mshv = ["vfio-ioctls/mshv"]
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
thiserror = "1.0.40" thiserror = "1.0.38"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false } 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" vmm-sys-util = "0.11.0"

View File

@@ -110,7 +110,8 @@ impl Bus {
let devices = self.devices.read().unwrap(); let devices = self.devices.read().unwrap();
let (range, dev) = devices let (range, dev) = devices
.range(..=BusRange { base: addr, len: 1 }) .range(..=BusRange { base: addr, len: 1 })
.next_back()?; .rev()
.next()?;
dev.upgrade().map(|d| (*range, d.clone())) dev.upgrade().map(|d| (*range, d.clone()))
} }

View File

@@ -5,10 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
anyhow = "1.0.71" anyhow = "1.0.69"
thiserror = "1.0.40" thiserror = "1.0.38"
serde = { version = "1.0.164", features = ["rc", "derive"] } serde = { version = "1.0.151", features = ["rc", "derive"] }
serde_json = "1.0.96" serde_json = "1.0.93"
versionize = "0.1.10" versionize = "0.1.9"
versionize_derive = "0.1.4" 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"] }

Some files were not shown because too many files have changed in this diff Show More