Compare commits

..

44 Commits
v34.0 ... v31.2

Author SHA1 Message Date
Bo Chen
3a63fa2613 build: Release v31.2 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-07-06 14:55:05 -07:00
Bo Chen
3a63143f33 misc: Address clippy beta issues
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-07-05 09:36:08 -07:00
Rob Bradford
064c1e2c8b virtio-devices: Avoid clashing names in imports
Don't import via glob to avoid (unused) objects colliding in the
namespace. This fixes a beta clippy issue.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2023-07-05 09:36:08 -07:00
Rob Bradford
15b9d14876 net_gen: Avoid clashing names in imports
Remove use of glob imports to fix an issue detected by clippy.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2023-07-05 09:36:08 -07:00
Alyssa Ross
9da363e79b vmm: ignore and warn TAP FDs send in vm.create
This does the same thing as df2a7c17 ("vmm: Ignore and warn TAP FDs
sent via the HTTP request body"), but for the vm.create endpoint,
which also previously would accept file descriptors in the body, and
try to use whatever fd occupied that number as a TAP device.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-07-05 09:36:08 -07:00
Alyssa Ross
bbfd810c3b vmm: allow restart_syscall() in PTY process
This can be triggered by debugging cloud-hypervisor using gdb, or
probably if the process is suspended and restarted.

Fixes: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/5489
Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-07-05 09:36:08 -07:00
Jianyong Wu
8fb86d2284 vfio: fix vfio device fail to initialize issue for 64k page size
Currently, vfio device fails to initialize as the msix-cap region in BAR
is mapped as RW region.

To resolve the initialization issue, this commit avoids mapping the
msix-cap region in the BAR. However, this solution introduces another
problem where aligning the msix table offset in the BAR to the page
size may cause overlap with the MMIO RW region, leading to reduced
performance. By enlarging the entire region in the BAR and relocating
the msix table to achieve page size alignment, this problem can be
overcomed effectively.

Fixes: #5292
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
2023-07-05 09:36:08 -07:00
Jianyong Wu
797110cca1 vm-allocator: Add page size related functions
To avoid code duplication extract page related functions to their
own module and add utility functions for manipulating addresses
related to page sizes

Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
2023-07-05 09:36:08 -07:00
Bo Chen
19ca5c0b84 vmm: Clarify memory regions are required to be page-size aligned
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-07-05 09:36:08 -07:00
Bo Chen
9fe9b8504d arch: Refactor the way of creating memory mapping
This patch clarifies the assumptions we have regarding the guest address
space layout while creating memory mapping in E820 on x86_64 and fdt on
aarch64. It also explicitly checks on these assumptions and report
errors if these assumptions do not hold.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-07-05 09:36:08 -07:00
Yu Li
4fc3dd5004 vmm: memory_manager: align down the rest space of ram_region
This commit renames `ram_region_sub_size` to `ram_region_available_size`
and make its value align down to the default page size or hugepage
size of the current memory zone, which can prevent the memory zone from
being split into misaligned parts.  And if the available size of ram
region is zero, this region will be marked as consumed even it has
unused space.

Note that there is two methods to use hugepages.

1. Specify `hugepages` for `memory` or `memory-zone`, if the
   `hugepage_size` is not specified, the value can be got by `statfs`
   for `/dev/hugepages`.
2. Specify a `file` in hugetlbfs for `memory-zone`, the hugepage size
   can also be got by `statfs` for the file.

The value for alignment will be the hugepage size if this memory zone
is using hugepages, otherwise the value will be default page size of
system.

Fixes: #5463

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-07-05 09:36:08 -07:00
Yu Li
6bc6365c35 arch: let arch_memory_regions return all available regions
The previous `arch_memory_regions` function will provide some memory
regions with the specified memory size and fill all the previous
regions before using the next one, but sometimes there may be no need
to fill up the previous one, e.g., the previous one should be aligned
with hugepage size.

This commit make `arch_memory_regions` function not take any
parameters and return the max available regions, the memory manager
can use them on demand.

Fixes: #5463

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-07-05 09:36:08 -07:00
Yu Li
e139cdfd69 arch: create memory mapping by the actual memory info
The original codes did not consider that the previous memory region
might not be full and always set it to the maximum size.

This commit fixes this problem by creating memory mappings based on
the actual memory details in both E820 on x86_64 and fdt on aarch64.

Fixes: #5463

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-07-05 09:36:08 -07:00
Yu Li
541de8b757 logger: use write with \r\n instead of writeln
The device manager will set tty or pty to raw mode, all the `\n` will
be LF without CR, which makes the output difficult to read.

This commit solves it by using `write` with `\r\n` instead of
`writeln`, which can print CR and LF explicitly.

Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-07-05 09:36:08 -07:00
Yu Li
184dac70a0 vmm: use unwrap_or instead of match for prefault
Signed-off-by: Yu Li <liyu.yukiteru@bytedance.com>
2023-07-05 09:36:08 -07:00
Jianyong Wu
022b489e7b arch: x86_64: Populate the APIC Id
Program the APIC ID (CPUID leaf 0x1 EBX) with the CPU id. This resolves
an issue where the EDKII firmware expects the APIC ID to vary per-CPU.

Fixes: #5475
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
2023-07-05 09:36:08 -07:00
Alyssa Ross
399e2f9f7d vmm, virtio-devices: allow mremap for consoles
SerialBuffer uses VecDeque::extend, which calls realloc, which a
maximum buffer size of 1 MiB.  Starting at allocation sizes of
128 KiB, musl's mallocng allocator will use mremap for the allocation.
Since this was not permitted by the seccomp rules, heavy write load
could crash cloud-hypervisor with a seccomp failure.  (Encountered
using virtio-console, but I don't see any reason it wouldn't happen
for the legacy serial device too.)

Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-07-05 09:36:08 -07:00
Rafael Mendonca
22cc96494f main: Fix error propagation if starting the VM fails
Commit 21d40d7 ("main: reset tty if starting the VM fails") changed
start_vmm() to join the vmm thread if an error happens after the vmm
thread is started. The implementation put all the error-prone code that
is run after the vmm is started in a closure, to be able to always join
the vmm thread, regardless of any error happening. However, it missed
propagating the error that might happen inside the closure back to the
main function, after joining the vmm thread.

For some cmd line options, the above issue inhibits proper error
reporting when starting a VM with invalid commands, as many parameters
are parsed after the vmm is started, thus if such parsing fails, no
error will be reported back to the user.

See: #5435
Fixes: 21d40d7 ("main: reset tty if starting the VM fails")
Signed-off-by: Rafael Mendonca <rafaelmendsr@gmail.com>
2023-07-05 09:36:08 -07:00
Bo Chen
f98402ec15 vmm: Allocate guest memory address space before TDX initialization
The refactoring on deferring address space allocation (#5169) broke TDX,
as TDX initialization needs to access guest memory for encryption and
measurement of guest pages.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-07-05 09:36:08 -07:00
Jianyong Wu
acc54ade7b vfio: align memory region size and address to PAGE_SIZE
In current implementation, memory region used in vfio is assumed to
align to 4k which may cause error when the PAGE_SIZE is not 4k, like on
Arm, it can be 16k and 64k.

Remove this assumption and align memory resource used by vfio to
PAGE_SIZE then vfio can run on host with 64k PAGE_SIZE.

Fixes: #5292
Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
2023-07-05 09:36:08 -07:00
Alyssa Ross
0ebbb3f8a2 vmm: allow getdents64 in seccomp filter
This is used on older kernels where close_range() is not available.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
Fixes: 505f4dfa ("vmm: close all unused fds in sigwinch listener")
2023-07-05 09:36:08 -07:00
Anatol Belski
95511287ec tests: Enable topology integration tests under mshv
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2023-07-05 09:36:08 -07:00
Anatol Belski
5a3af30e6a seccomp: Add filter entry for MSHV_VP_REGISTER_INTERCEPT_RESULT
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2023-07-05 09:36:08 -07:00
Anatol Belski
034b48faf7 mshv: Pass topology explicitly while constructing cpuid
Unlike KVM, there's no internal handling for topoolgy under MSHV. Thus,
if no topology has been passed during the CH launch, use the boot CPUs
count to construct the topology struct.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2023-07-05 09:36:08 -07:00
Anatol Belski
ba3e02ce86 hypervisor: mshv: Implement set_cpuid2 call
Passing the CPUID leafs with the topology is integrated into the common
mechanism of setting and patching CPUID in Cloud Hypervisor. All the
CPUID values will be passed to the hypervisor through the register
intercept call.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
2023-07-05 09:36:08 -07:00
Alyssa Ross
5492259af9 main: reset tty if starting the VM fails
When I refactored this to centralise resetting the tty into
DeviceManager::drop, I tested that the tty was reset if an error
happened on the vmm thread, but not on the main thread.  It turns out
that if an error happened on the main thread, the process would just
exit, so drop handlers on other threads wouldn't get run.

To fix this, I've changed start_vmm() to write to the VMM's exit
eventfd and then join the thread if an error happens after the vmm
thread is started.

Fixes: b6feae0a ("vmm: only touch the tty flags if it's being used")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-07-05 09:36:08 -07:00
Alyssa Ross
cc1254d5e1 vmm: reset to the original termios
Previously, we used two different functions for configuring ttys.
vmm_sys_util::terminal::Terminal::set_raw_mode() was used to configure
stdio ttys, and cfmakeraw() was used to configure ptys created by
cloud-hypervisor.  When I centralized the stdio tty cleanup, I also
switched to using cfmakeraw() everywhere, to avoid duplication.

cfmakeraw sets the OPOST flag, but when we later reset the ttys, we
used vmm_sys_util::terminal::Terminal::set_canon_mode(), which does
not unset this flag.  This meant that the terminal was getting mostly,
but not fully, reset.

To fix this without depending on the implementation of cfmakeraw(),
let's just store the original termios for stdio terminals, and restore
them to exactly the state we found them in when cloud-hypervisor exits.

Fixes: b6feae0a ("vmm: only touch the tty flags if it's being used")
Signed-off-by: Alyssa Ross <hi@alyssa.is>
2023-07-05 09:36:08 -07:00
Rob Bradford
34bb3319d4 hypervisor, vmm: Limit max number of vCPUs to hypervisor maximum
On KVM this is provided by an ioctl, on MSHV this is constant. Although
there is a HV_MAXIMUM_PROCESSORS constant the MSHV ioctl API is limited
to u8.

Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
2023-07-05 09:36:08 -07:00
Bo Chen
d530569ac2 build: Release v31.1 (bug fix release)
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 16:41:02 -07:00
Bo Chen
75956e64ec 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 10:47:33 -07:00
Bo Chen
ae646c2a00 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 10:47:33 -07:00
Bo Chen
04d3e5bbf5 vmm: Add unit test for 'VmConfig::preserved_fds'
Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 10:47:33 -07:00
Bo Chen
cbe972659c 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 10:47:33 -07:00
Bo Chen
1e4e03d110 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 10:47:33 -07:00
Bo Chen
4876f7550d Revert "vmm: config: Implement Clone for NetConfig"
This reverts commit ea4a95c4f6.

Signed-off-by: Bo Chen <chen.bo@intel.com>
2023-04-18 10:47:33 -07:00
Bo Chen
c0146e3ef1 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 10:47:33 -07:00
Bo Chen
77a205881b 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 10:47:33 -07:00
Bo Chen
321421c53e 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 10:47:33 -07:00
Bo Chen
48a87e699d 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 10:47:33 -07:00
Alyssa Ross
147a800d5d 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 10:47:33 -07:00
Alyssa Ross
eaf8cbd47d 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 10:47:33 -07:00
Alyssa Ross
9d24e862eb 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 10:47:33 -07:00
Alyssa Ross
11324ac21c 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 10:47:33 -07:00
Bo Chen
ce75865e2c 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 10:47:33 -07:00
153 changed files with 2015 additions and 6011 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

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

@@ -28,13 +28,13 @@ jobs:
with: with:
toolchain: "1.67.1" toolchain: "1.67.1"
command: build command: build
args: --all --release --features 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.67.1"
command: build command: build
args: --all --release --features 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:

1379
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 = "34.0.0" version = "31.2.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,48 +29,44 @@ 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 }
epoll = "4.3.3" epoll = "4.3.1"
event_monitor = { path = "event_monitor" } event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" } hypervisor = { path = "hypervisor" }
libc = "0.2.139" 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.95"
signal-hook = "0.3.17" signal-hook = "0.3.15"
thiserror = "1.0.40" thiserror = "1.0.39"
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.18.0" once_cell = "1.17.1"
serde_json = "1.0.96" serde_json = "1.0.95"
test_infra = { path = "test_infra" } test_infra = { path = "test_infra" }
wait-timeout = "0.2.0" wait-timeout = "0.2.0"
[features] [features]
default = ["kvm", "io_uring"] 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"]
io_uring = ["vmm/io_uring"]
kvm = ["vmm/kvm"] kvm = ["vmm/kvm"]
mshv = ["vmm/mshv"] mshv = ["vmm/mshv"]
tdx = ["vmm/tdx"] tdx = ["vmm/tdx"]
@@ -80,7 +76,7 @@ tracing = ["vmm/tracing", "tracer/tracing"]
members = [ members = [
"api_client", "api_client",
"arch", "arch",
"block", "block_util",
"devices", "devices",
"event_monitor", "event_monitor",
"hypervisor", "hypervisor",
@@ -89,10 +85,12 @@ members = [
"option_parser", "option_parser",
"pci", "pci",
"performance-metrics", "performance-metrics",
"qcow",
"rate_limiter", "rate_limiter",
"serial_buffer", "serial_buffer",
"test_infra", "test_infra",
"tracer", "tracer",
"vhdx",
"vhost_user_block", "vhost_user_block",
"vhost_user_net", "vhost_user_net",
"virtio-devices", "virtio-devices",

337
Jenkinsfile vendored
View File

@@ -117,63 +117,6 @@ pipeline {
} }
} }
} }
stage('Worker build - AMD') {
agent { node { label 'jammy-amd' } }
when {
beforeAgent true
expression {
return runWorkers
}
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Prepare environment') {
steps {
sh 'scripts/prepare_vdpa.sh'
}
}
stage('Run integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration'
}
}
stage('Run live-migration integration tests') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration --integration -- -- --skip live_migration::live_migration_parallel::test_live_upgrade_watchdog --skip live_migration::live_migration_parallel::test_live_upgrade_watchdog_local'
}
}
stage('Run integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration --libc musl'
}
}
stage('Run live-migration integration tests for musl') {
options {
timeout(time: 1, unit: 'HOURS')
}
steps {
sh 'sudo modprobe openvswitch'
sh 'scripts/dev_cli.sh tests --integration-live-migration --libc musl -- -- --skip live_migration::live_migration_parallel::test_live_upgrade_watchdog --skip live_migration::live_migration_parallel::test_live_upgrade_watchdog_local'
}
}
}
}
stage('AArch64 worker build') { stage('AArch64 worker build') {
agent { node { label 'bionic-arm64' } } agent { node { label 'bionic-arm64' } }
when { when {
@@ -295,146 +238,146 @@ pipeline {
} }
} }
} }
// stage('Worker build - Metrics') { stage('Worker build - Metrics') {
// agent { node { label 'jammy-metrics' } } agent { node { label 'jammy-metrics' } }
// when { when {
// branch 'main' branch 'main'
// beforeAgent true beforeAgent true
// expression { expression {
// return runWorkers return runWorkers
// } }
// } }
// environment { environment {
// METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f') METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
// } }
// stages { stages {
// stage('Checkout') { stage('Checkout') {
// steps { steps {
// checkout scm checkout scm
// } }
// } }
// stage('Run metrics tests') { stage('Run metrics tests') {
// options { options {
// timeout(time: 1, unit: 'HOURS') timeout(time: 1, unit: 'HOURS')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json' sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
// } }
// } }
// stage('Upload metrics report') { stage('Upload metrics report') {
// steps { steps {
// sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json' sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
// } }
// } }
// } }
// } }
// stage('Worker build - Rate Limiter') { stage('Worker build - Rate Limiter') {
// agent { node { label 'focal-metrics' } } agent { node { label 'focal-metrics' } }
// when { when {
// branch 'main' branch 'main'
// beforeAgent true beforeAgent true
// expression { expression {
// return runWorkers return runWorkers
// } }
// } }
// stages { stages {
// stage('Checkout') { stage('Checkout') {
// steps { steps {
// checkout scm checkout scm
// } }
// } }
// stage('Run rate-limiter integration tests') { stage('Run rate-limiter integration tests') {
// options { options {
// timeout(time: 10, unit: 'MINUTES') timeout(time: 10, unit: 'MINUTES')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --integration-rate-limiter' sh 'scripts/dev_cli.sh tests --integration-rate-limiter'
// } }
// } }
// } }
// } }
// stage('Worker build - SGX') { stage('Worker build - SGX') {
// agent { node { label 'jammy-sgx' } } agent { node { label 'jammy-sgx' } }
// when { when {
// beforeAgent true beforeAgent true
// allOf { allOf {
// branch 'main' branch 'main'
// expression { expression {
// return runWorkers return runWorkers
// } }
// } }
// } }
// stages { stages {
// stage('Checkout') { stage('Checkout') {
// steps { steps {
// checkout scm checkout scm
// } }
// } }
// stage('Run SGX integration tests') { stage('Run SGX integration tests') {
// options { options {
// timeout(time: 1, unit: 'HOURS') timeout(time: 1, unit: 'HOURS')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --integration-sgx' sh 'scripts/dev_cli.sh tests --integration-sgx'
// } }
// } }
// stage('Run SGX integration tests for musl') { stage('Run SGX integration tests for musl') {
// options { options {
// timeout(time: 1, unit: 'HOURS') timeout(time: 1, unit: 'HOURS')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl' sh 'scripts/dev_cli.sh tests --integration-sgx --libc musl'
// } }
// } }
// } }
// post { post {
// always { always {
// sh "sudo chown -R jenkins.jenkins ${WORKSPACE}" sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
// deleteDir() deleteDir()
// } }
// } }
// } }
// stage('Worker build - VFIO') { stage('Worker build - VFIO') {
// agent { node { label 'jammy-vfio' } } agent { node { label 'jammy-vfio' } }
// when { when {
// beforeAgent true beforeAgent true
// allOf { allOf {
// branch 'main' branch 'main'
// expression { expression {
// return runWorkers return runWorkers
// } }
// } }
// } }
// stages { stages {
// stage('Checkout') { stage('Checkout') {
// steps { steps {
// checkout scm checkout scm
// } }
// } }
// stage('Run VFIO integration tests') { stage('Run VFIO integration tests') {
// options { options {
// timeout(time: 1, unit: 'HOURS') timeout(time: 1, unit: 'HOURS')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --integration-vfio' sh 'scripts/dev_cli.sh tests --integration-vfio'
// } }
// } }
// stage('Run VFIO integration tests for musl') { stage('Run VFIO integration tests for musl') {
// options { options {
// timeout(time: 1, unit: 'HOURS') timeout(time: 1, unit: 'HOURS')
// } }
// steps { steps {
// sh 'scripts/dev_cli.sh tests --integration-vfio --libc musl' sh 'scripts/dev_cli.sh tests --integration-vfio --libc musl'
// } }
// } }
// } }
// post { post {
// always { always {
// sh "sudo chown -R jenkins.jenkins ${WORKSPACE}" sh "sudo chown -R jenkins.jenkins ${WORKSPACE}"
// deleteDir() deleteDir()
// } }
// } }
// } }
} }
} }
} }

View File

@@ -78,9 +78,9 @@ The following sections describe how to build and run Cloud Hypervisor.
## Host OS ## Host OS
For required KVM functionality and adequate performance the recommended host For required KVM functionality the minimum host kernel version is 4.11. For
kernel version is 5.13. The majority of the CI currently tests with kernel adequate performance the minimum recommended host kernel version is 5.6. The
version 5.15. majority of the CI currently tests with kernel version 5.15.
## Use Pre-built Binaries ## Use Pre-built Binaries
@@ -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

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.39"
uuid = "1.3.4" uuid = "1.3.0"
versionize = "0.1.10" versionize = "0.1.10"
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")?;

View File

@@ -180,8 +180,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.

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,
@@ -39,6 +39,7 @@ const MTRR_EDX_BIT: u8 = 12; // Hypervisor ecx bit.
const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX const INVARIANT_TSC_EDX_BIT: u8 = 8; // Invariant TSC bit on 0x8000_0007 EDX
// KVM feature bits // KVM feature bits
const KVM_FEATURE_ASYNC_PF_INT_BIT: u8 = 14;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
const KVM_FEATURE_CLOCKSOURCE_BIT: u8 = 0; const KVM_FEATURE_CLOCKSOURCE_BIT: u8 = 0;
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
@@ -209,6 +210,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,
@@ -674,7 +676,14 @@ pub fn generate_common_cpuid(
0x8000_0008 => { 0x8000_0008 => {
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff); entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
} }
// Disable KVM_FEATURE_ASYNC_PF_INT
// This is required until we find out why the asynchronous page
// fault is generating unexpected behavior when using interrupt
// mechanism.
// TODO: Re-enable KVM_FEATURE_ASYNC_PF_INT (#2277)
0x4000_0001 => { 0x4000_0001 => {
entry.eax &= !(1 << KVM_FEATURE_ASYNC_PF_INT_BIT);
// These features are not supported by TDX // These features are not supported by TDX
#[cfg(feature = "tdx")] #[cfg(feature = "tdx")]
if tdx_enabled { if tdx_enabled {
@@ -1007,7 +1016,7 @@ fn configure_pvh(
} }
info!( info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}", "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
high_ram_start, first_region_end high_ram_start, first_region_end
); );
@@ -1033,7 +1042,7 @@ fn configure_pvh(
} }
info!( info!(
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}", "create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
ram_64bit_start, second_region_end ram_64bit_start, second_region_end
); );
add_memmap_entry( add_memmap_entry(
@@ -1131,7 +1140,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);
@@ -1140,7 +1149,9 @@ pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u
// Some physical address bits may become reserved when the feature is enabled. // 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

View File

@@ -1,27 +0,0 @@
[package]
name = "block"
version = "0.1.0"
edition = "2021"
authors = ["The Cloud Hypervisor Authors", "The Chromium OS Authors"]
[features]
default = []
io_uring = ["dep:io-uring"]
[dependencies]
byteorder = "1.4.3"
crc32c = "0.6.3"
io-uring = { version = "0.6.0", optional = true }
libc = "0.2.139"
log = "0.4.17"
remain = "0.2.11"
smallvec = "1.10.0"
thiserror = "1.0.40"
uuid = { version = "1.3.4", features = ["v4"] }
versionize = "0.1.10"
versionize_derive = "0.1.4"
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.8.0"
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0"

View File

@@ -1,90 +0,0 @@
// Copyright © 2021 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
use crate::vhd::VhdFooter;
use crate::BlockBackend;
use std::fs::File;
use std::io::{Read, Seek, SeekFrom, Write};
use std::os::unix::io::{AsRawFd, RawFd};
#[derive(Debug)]
pub struct FixedVhd {
file: File,
size: u64,
position: u64,
}
impl FixedVhd {
pub fn new(mut file: File) -> std::io::Result<Self> {
let footer = VhdFooter::new(&mut file)?;
Ok(Self {
file,
size: footer.current_size(),
position: 0,
})
}
}
impl AsRawFd for FixedVhd {
fn as_raw_fd(&self) -> RawFd {
self.file.as_raw_fd()
}
}
impl Read for FixedVhd {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self.file.read(buf) {
Ok(r) => {
self.position = self.position.checked_add(r.try_into().unwrap()).unwrap();
Ok(r)
}
Err(e) => Err(e),
}
}
}
impl Write for FixedVhd {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match self.file.write(buf) {
Ok(r) => {
self.position = self.position.checked_add(r.try_into().unwrap()).unwrap();
Ok(r)
}
Err(e) => Err(e),
}
}
fn flush(&mut self) -> std::io::Result<()> {
self.file.sync_all()
}
}
impl Seek for FixedVhd {
fn seek(&mut self, newpos: SeekFrom) -> std::io::Result<u64> {
match self.file.seek(newpos) {
Ok(pos) => {
self.position = pos;
Ok(pos)
}
Err(e) => Err(e),
}
}
}
impl BlockBackend for FixedVhd {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.size)
}
}
impl Clone for FixedVhd {
fn clone(&self) -> Self {
Self {
file: self.file.try_clone().expect("FixedVhd cloning failed"),
size: self.size,
position: self.position,
}
}
}

25
block_util/Cargo.toml Normal file
View File

@@ -0,0 +1,25 @@
[package]
name = "block_util"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
[features]
default = []
[dependencies]
io-uring = "0.5.13"
libc = "0.2.139"
log = "0.4.17"
qcow = { path = "../qcow" }
smallvec = "1.10.0"
thiserror = "1.0.39"
versionize = "0.1.10"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.7.1"
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.11.0"

View File

@@ -5,29 +5,36 @@
use crate::async_io::{ use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
}; };
use crate::fixed_vhd::FixedVhd;
use crate::raw_async::RawFileAsync; use crate::raw_async::RawFileAsync;
use crate::BlockBackend; use crate::vhd::VhdFooter;
use std::fs::File; use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct FixedVhdDiskAsync(FixedVhd); pub struct FixedVhdDiskAsync {
file: File,
size: u64,
}
impl FixedVhdDiskAsync { impl FixedVhdDiskAsync {
pub fn new(file: File) -> std::io::Result<Self> { pub fn new(mut file: File) -> std::io::Result<Self> {
Ok(Self(FixedVhd::new(file)?)) let footer = VhdFooter::new(&mut file)?;
Ok(FixedVhdDiskAsync {
file,
size: footer.current_size(),
})
} }
} }
impl DiskFile for FixedVhdDiskAsync { impl DiskFile for FixedVhdDiskAsync {
fn size(&mut self) -> DiskFileResult<u64> { fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size().unwrap()) Ok(self.size)
} }
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> { fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
FixedVhdAsync::new(self.0.as_raw_fd(), ring_depth, self.0.size().unwrap()) FixedVhdAsync::new(self.file.as_raw_fd(), ring_depth, self.size)
.map_err(DiskFileError::NewAsyncIo)?, .map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>) ) as Box<dyn AsyncIo>)
} }

View File

@@ -5,29 +5,36 @@
use crate::async_io::{ use crate::async_io::{
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
}; };
use crate::fixed_vhd::FixedVhd;
use crate::raw_sync::RawFileSync; use crate::raw_sync::RawFileSync;
use crate::BlockBackend; use crate::vhd::VhdFooter;
use std::fs::File; use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct FixedVhdDiskSync(FixedVhd); pub struct FixedVhdDiskSync {
file: File,
size: u64,
}
impl FixedVhdDiskSync { impl FixedVhdDiskSync {
pub fn new(file: File) -> std::io::Result<Self> { pub fn new(mut file: File) -> std::io::Result<Self> {
Ok(Self(FixedVhd::new(file)?)) let footer = VhdFooter::new(&mut file)?;
Ok(FixedVhdDiskSync {
file,
size: footer.current_size(),
})
} }
} }
impl DiskFile for FixedVhdDiskSync { impl DiskFile for FixedVhdDiskSync {
fn size(&mut self) -> DiskFileResult<u64> { fn size(&mut self) -> DiskFileResult<u64> {
Ok(self.0.size().unwrap()) Ok(self.size)
} }
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> { fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
Ok(Box::new( Ok(Box::new(
FixedVhdSync::new(self.0.as_raw_fd(), self.0.size().unwrap()) FixedVhdSync::new(self.file.as_raw_fd(), self.size)
.map_err(DiskFileError::NewAsyncIo)?, .map_err(DiskFileError::NewAsyncIo)?,
) as Box<dyn AsyncIo>) ) as Box<dyn AsyncIo>)
} }

View File

@@ -12,35 +12,21 @@
extern crate log; extern crate log;
pub mod async_io; pub mod async_io;
pub mod fixed_vhd;
#[cfg(feature = "io_uring")]
/// Enabled with the `"io_uring"` feature
pub mod fixed_vhd_async; pub mod fixed_vhd_async;
pub mod fixed_vhd_sync; pub mod fixed_vhd_sync;
pub mod qcow;
pub mod qcow_sync; pub mod qcow_sync;
#[cfg(feature = "io_uring")]
/// Async primitives based on `io-uring`
///
/// Enabled with the `"io_uring"` feature
pub mod raw_async; pub mod raw_async;
pub mod raw_sync; pub mod raw_sync;
pub mod vhd; pub mod vhd;
pub mod vhdx;
pub mod vhdx_sync; pub mod vhdx_sync;
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult}; use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
use crate::fixed_vhd::FixedVhd;
use crate::qcow::{QcowFile, RawFile};
use crate::vhdx::{Vhdx, VhdxError};
#[cfg(feature = "io_uring")]
use io_uring::{opcode, IoUring, Probe}; use io_uring::{opcode, IoUring, Probe};
use smallvec::SmallVec; use smallvec::SmallVec;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::cmp; use std::cmp;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt::Debug;
use std::fs::File; use std::fs::File;
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
use std::os::linux::fs::MetadataExt; use std::os::linux::fs::MetadataExt;
@@ -80,22 +66,12 @@ pub enum Error {
DescriptorChainTooShort, DescriptorChainTooShort,
#[error("Guest gave us a descriptor that was too short to use")] #[error("Guest gave us a descriptor that was too short to use")]
DescriptorLengthTooSmall, DescriptorLengthTooSmall,
#[error("Failed to detect image type: {0}")]
DetectImageType(std::io::Error),
#[error("Failure in fixed vhd: {0}")]
FixedVhdError(std::io::Error),
#[error("Getting a block's metadata fails for any reason")] #[error("Getting a block's metadata fails for any reason")]
GetFileMetadata, GetFileMetadata,
#[error("The requested operation would cause a seek beyond disk end")] #[error("The requested operation would cause a seek beyond disk end")]
InvalidOffset, InvalidOffset,
#[error("Failure in qcow: {0}")]
QcowError(qcow::Error),
#[error("Failure in raw file: {0}")]
RawFileError(std::io::Error),
#[error("The requested operation does not support multiple descriptors")] #[error("The requested operation does not support multiple descriptors")]
TooManyDescriptors, TooManyDescriptors,
#[error("Failure in vhdx: {0}")]
VhdxError(VhdxError),
} }
fn build_device_id(disk_path: &Path) -> result::Result<String, Error> { fn build_device_id(disk_path: &Path) -> result::Result<String, Error> {
@@ -567,59 +543,50 @@ unsafe impl ByteValued for VirtioBlockGeometry {}
/// Check if io_uring for block device can be used on the current system, as /// Check if io_uring for block device can be used on the current system, as
/// it correctly supports the expected io_uring features. /// it correctly supports the expected io_uring features.
pub fn block_io_uring_is_supported() -> bool { pub fn block_io_uring_is_supported() -> bool {
#[cfg(not(feature = "io_uring"))] let error_msg = "io_uring not supported:";
{
info!("io_uring is disabled by crate features"); // Check we can create an io_uring instance, which effectively verifies
false // that io_uring_setup() syscall is supported.
let io_uring = match IoUring::new(1) {
Ok(io_uring) => io_uring,
Err(e) => {
info!("{} failed to create io_uring instance: {}", error_msg, e);
return false;
}
};
let submitter = io_uring.submitter();
let mut probe = Probe::new();
// Check we can register a probe to validate supported operations.
match submitter.register_probe(&mut probe) {
Ok(_) => {}
Err(e) => {
info!("{} failed to register a probe: {}", error_msg, e);
return false;
}
} }
#[cfg(feature = "io_uring")] // Check IORING_OP_FSYNC is supported
{ if !probe.is_supported(opcode::Fsync::CODE) {
let error_msg = "io_uring not supported:"; info!("{} IORING_OP_FSYNC operation not supported", error_msg);
return false;
// Check we can create an io_uring instance, which effectively verifies
// that io_uring_setup() syscall is supported.
let io_uring = match IoUring::new(1) {
Ok(io_uring) => io_uring,
Err(e) => {
info!("{} failed to create io_uring instance: {}", error_msg, e);
return false;
}
};
let submitter = io_uring.submitter();
let mut probe = Probe::new();
// Check we can register a probe to validate supported operations.
match submitter.register_probe(&mut probe) {
Ok(_) => {}
Err(e) => {
info!("{} failed to register a probe: {}", error_msg, e);
return false;
}
}
// Check IORING_OP_FSYNC is supported
if !probe.is_supported(opcode::Fsync::CODE) {
info!("{} IORING_OP_FSYNC operation not supported", error_msg);
return false;
}
// Check IORING_OP_READV is supported
if !probe.is_supported(opcode::Readv::CODE) {
info!("{} IORING_OP_READV operation not supported", error_msg);
return false;
}
// Check IORING_OP_WRITEV is supported
if !probe.is_supported(opcode::Writev::CODE) {
info!("{} IORING_OP_WRITEV operation not supported", error_msg);
return false;
}
true
} }
// Check IORING_OP_READV is supported
if !probe.is_supported(opcode::Readv::CODE) {
info!("{} IORING_OP_READV operation not supported", error_msg);
return false;
}
// Check IORING_OP_WRITEV is supported
if !probe.is_supported(opcode::Writev::CODE) {
info!("{} IORING_OP_WRITEV operation not supported", error_msg);
return false;
}
true
} }
pub trait AsyncAdaptor<F> pub trait AsyncAdaptor<F>
@@ -753,26 +720,3 @@ pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
Ok(image_type) Ok(image_type)
} }
pub trait BlockBackend: Read + Write + Seek + Send + Debug {
fn size(&self) -> Result<u64, Error>;
}
/// Inspect the image file type and create an appropriate disk file to match it.
pub fn create_disk_file(mut file: File, direct_io: bool) -> Result<Box<dyn BlockBackend>, Error> {
let image_type = detect_image_type(&mut file).map_err(Error::DetectImageType)?;
Ok(match image_type {
ImageType::Qcow2 => {
Box::new(QcowFile::from(RawFile::new(file, direct_io)).map_err(Error::QcowError)?)
as Box<dyn BlockBackend>
}
ImageType::FixedVhd => {
Box::new(FixedVhd::new(file).map_err(Error::FixedVhdError)?) as Box<dyn BlockBackend>
}
ImageType::Vhdx => {
Box::new(Vhdx::new(file).map_err(Error::VhdxError)?) as Box<dyn BlockBackend>
}
ImageType::Raw => Box::new(RawFile::new(file, direct_io)) as Box<dyn BlockBackend>,
})
}

View File

@@ -3,8 +3,8 @@
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult}; use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::qcow::{QcowFile, RawFile, Result as QcowResult};
use crate::AsyncAdaptor; use crate::AsyncAdaptor;
use qcow::{QcowFile, RawFile, Result as QcowResult};
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};

View File

@@ -86,7 +86,7 @@ impl AsyncIo for RawFileAsync {
let _ = unsafe { let _ = unsafe {
sq.push( sq.push(
&opcode::Readv::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32) &opcode::Readv::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32)
.offset(offset.try_into().unwrap()) .offset(offset)
.build() .build()
.flags(squeue::Flags::ASYNC) .flags(squeue::Flags::ASYNC)
.user_data(user_data), .user_data(user_data),
@@ -114,7 +114,7 @@ impl AsyncIo for RawFileAsync {
let _ = unsafe { let _ = unsafe {
sq.push( sq.push(
&opcode::Writev::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32) &opcode::Writev::new(types::Fd(self.fd), iovecs.as_ptr(), iovecs.len() as u32)
.offset(offset.try_into().unwrap()) .offset(offset)
.build() .build()
.flags(squeue::Flags::ASYNC) .flags(squeue::Flags::ASYNC)
.user_data(user_data), .user_data(user_data),

View File

@@ -73,7 +73,7 @@ impl AsyncIo for RawFileSync {
let result = unsafe { let result = unsafe {
libc::preadv( libc::preadv(
self.fd as libc::c_int, self.fd as libc::c_int,
iovecs.as_ptr(), iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int, iovecs.len() as libc::c_int,
offset, offset,
) )
@@ -98,7 +98,7 @@ impl AsyncIo for RawFileSync {
let result = unsafe { let result = unsafe {
libc::pwritev( libc::pwritev(
self.fd as libc::c_int, self.fd as libc::c_int,
iovecs.as_ptr(), iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int, iovecs.len() as libc::c_int,
offset, offset,
) )

View File

@@ -3,11 +3,11 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult}; use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
use crate::vhdx::{Result as VhdxResult, Vhdx};
use crate::AsyncAdaptor; use crate::AsyncAdaptor;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::{Arc, Mutex, MutexGuard};
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
pub struct VhdxDiskSync { pub struct VhdxDiskSync {

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,22 +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"
event_monitor = { path = "../event_monitor" }
hypervisor = { path = "../hypervisor" } hypervisor = { path = "../hypervisor" }
libc = "0.2.139" libc = "0.2.139"
log = "0.4.17" log = "0.4.17"
pci = { path = "../pci" } thiserror = "1.0.39"
thiserror = "1.0.40"
tpm = { path = "../tpm" } tpm = { path = "../tpm" }
versionize = "0.1.10" versionize = "0.1.10"
versionize_derive = "0.1.4" versionize_derive = "0.1.4"
vm-allocator = { path = "../vm-allocator" }
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

@@ -5,9 +5,7 @@
use super::AcpiNotificationFlags; use super::AcpiNotificationFlags;
use acpi_tables::{aml, Aml, AmlSink}; use acpi_tables::{aml, Aml, AmlSink};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Instant; use std::time::Instant;
use vm_device::interrupt::InterruptSourceGroup; use vm_device::interrupt::InterruptSourceGroup;
use vm_device::BusDevice; use vm_device::BusDevice;
@@ -20,20 +18,14 @@ pub const GED_DEVICE_ACPI_SIZE: usize = 0x1;
pub struct AcpiShutdownDevice { pub struct AcpiShutdownDevice {
exit_evt: EventFd, exit_evt: EventFd,
reset_evt: EventFd, reset_evt: EventFd,
vcpus_kill_signalled: Arc<AtomicBool>,
} }
impl AcpiShutdownDevice { impl AcpiShutdownDevice {
/// Constructs a device that will signal the given event when the guest requests it. /// Constructs a device that will signal the given event when the guest requests it.
pub fn new( pub fn new(exit_evt: EventFd, reset_evt: EventFd) -> AcpiShutdownDevice {
exit_evt: EventFd,
reset_evt: EventFd,
vcpus_kill_signalled: Arc<AtomicBool>,
) -> AcpiShutdownDevice {
AcpiShutdownDevice { AcpiShutdownDevice {
exit_evt, exit_evt,
reset_evt, reset_evt,
vcpus_kill_signalled,
} }
} }
} }
@@ -51,13 +43,6 @@ impl BusDevice for AcpiShutdownDevice {
if let Err(e) = self.reset_evt.write(1) { if let Err(e) = self.reset_evt.write(1) {
error!("Error triggering ACPI reset event: {}", e); error!("Error triggering ACPI reset event: {}", e);
} }
// Spin until we are sure the reset_evt has been handled and that when
// we return from the KVM_RUN we will exit rather than re-enter the guest.
while !self.vcpus_kill_signalled.load(Ordering::SeqCst) {
// This is more effective than thread::yield_now() at
// avoiding a priority inversion with the VMM thread
thread::sleep(std::time::Duration::from_millis(1));
}
} }
// The ACPI DSDT table specifies the S5 sleep state (shutdown) as value 5 // The ACPI DSDT table specifies the S5 sleep state (shutdown) as value 5
const S5_SLEEP_VALUE: u8 = 5; const S5_SLEEP_VALUE: u8 = 5;
@@ -68,13 +53,6 @@ impl BusDevice for AcpiShutdownDevice {
if let Err(e) = self.exit_evt.write(1) { if let Err(e) = self.exit_evt.write(1) {
error!("Error triggering ACPI shutdown event: {}", e); error!("Error triggering ACPI shutdown event: {}", e);
} }
// Spin until we are sure the reset_evt has been handled and that when
// we return from the KVM_RUN we will exit rather than re-enter the guest.
while !self.vcpus_kill_signalled.load(Ordering::SeqCst) {
// This is more effective than thread::yield_now() at
// avoiding a priority inversion with the VMM thread
thread::sleep(std::time::Duration::from_millis(1));
}
} }
None None
} }
@@ -138,7 +116,6 @@ 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(

View File

@@ -98,14 +98,9 @@ impl Gic {
i as InterruptIndex, i as InterruptIndex,
InterruptSourceConfig::LegacyIrq(config), InterruptSourceConfig::LegacyIrq(config),
false, false,
false,
) )
.map_err(Error::EnableInterrupt)?; .map_err(Error::EnableInterrupt)?;
} }
self.interrupt_source_group
.set_gsi()
.map_err(Error::EnableInterrupt)?;
Ok(()) Ok(())
} }

View File

@@ -237,14 +237,9 @@ impl Ioapic {
if state.is_some() { if state.is_some() {
for (irq, entry) in ioapic.used_entries.iter().enumerate() { for (irq, entry) in ioapic.used_entries.iter().enumerate() {
if *entry { if *entry {
ioapic.update_entry(irq, false)?; ioapic.update_entry(irq)?;
} }
} }
ioapic
.interrupt_source_group
.set_gsi()
.map_err(Error::UpdateInterrupt)?;
} }
Ok(ioapic) Ok(ioapic)
@@ -283,7 +278,7 @@ impl Ioapic {
} }
// The entry must be updated through the interrupt source // The entry must be updated through the interrupt source
// group. // group.
if let Err(e) = self.update_entry(index, true) { if let Err(e) = self.update_entry(index) {
error!("Failed updating IOAPIC entry: {:?}", e); error!("Failed updating IOAPIC entry: {:?}", e);
} }
// Store the information this IRQ is now being used. // Store the information this IRQ is now being used.
@@ -334,7 +329,7 @@ impl Ioapic {
} }
} }
fn update_entry(&self, irq: usize, set_gsi: bool) -> Result<()> { fn update_entry(&self, irq: usize) -> Result<()> {
let entry = self.reg_entries[irq]; let entry = self.reg_entries[irq];
// Validate Destination Mode value, and retrieve Destination ID // Validate Destination Mode value, and retrieve Destination ID
@@ -391,7 +386,6 @@ impl Ioapic {
irq as InterruptIndex, irq as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
interrupt_mask(entry) == 1, interrupt_mask(entry) == 1,
set_gsi,
) )
.map_err(Error::UpdateInterrupt)?; .map_err(Error::UpdateInterrupt)?;

View File

@@ -5,9 +5,7 @@
use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME}; use libc::{clock_gettime, gmtime_r, timespec, tm, CLOCK_REALTIME};
use std::cmp::min; use std::cmp::min;
use std::mem; use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Barrier}; use std::sync::{Arc, Barrier};
use std::thread;
use vm_device::BusDevice; use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@@ -25,19 +23,13 @@ pub struct Cmos {
index: u8, index: u8,
data: [u8; DATA_LEN], data: [u8; DATA_LEN],
reset_evt: EventFd, reset_evt: EventFd,
vcpus_kill_signalled: Option<Arc<AtomicBool>>,
} }
impl Cmos { impl Cmos {
/// Constructs a CMOS/RTC device with initial data. /// Constructs a CMOS/RTC device with initial data.
/// `mem_below_4g` is the size of memory in bytes below the 32-bit gap. /// `mem_below_4g` is the size of memory in bytes below the 32-bit gap.
/// `mem_above_4g` is the size of memory in bytes above the 32-bit gap. /// `mem_above_4g` is the size of memory in bytes above the 32-bit gap.
pub fn new( pub fn new(mem_below_4g: u64, mem_above_4g: u64, reset_evt: EventFd) -> Cmos {
mem_below_4g: u64,
mem_above_4g: u64,
reset_evt: EventFd,
vcpus_kill_signalled: Option<Arc<AtomicBool>>,
) -> Cmos {
let mut data = [0u8; DATA_LEN]; let mut data = [0u8; DATA_LEN];
// Extended memory from 16 MB to 4 GB in units of 64 KB // Extended memory from 16 MB to 4 GB in units of 64 KB
@@ -58,7 +50,6 @@ impl Cmos {
index: 0, index: 0,
data, data,
reset_evt, reset_evt,
vcpus_kill_signalled,
} }
} }
} }
@@ -76,15 +67,6 @@ impl BusDevice for Cmos {
if self.index == 0x8f && data[0] == 0 { if self.index == 0x8f && data[0] == 0 {
info!("CMOS reset"); info!("CMOS reset");
self.reset_evt.write(1).unwrap(); self.reset_evt.write(1).unwrap();
if let Some(vcpus_kill_signalled) = self.vcpus_kill_signalled.take() {
// Spin until we are sure the reset_evt has been handled and that when
// we return from the KVM_RUN we will exit rather than re-enter the guest.
while !vcpus_kill_signalled.load(Ordering::SeqCst) {
// This is more effective than thread::yield_now() at
// avoiding a priority inversion with the VMM thread
thread::sleep(std::time::Duration::from_millis(1));
}
}
} else { } else {
self.data[(self.index & INDEX_MASK) as usize] = data[0] self.data[(self.index & INDEX_MASK) as usize] = data[0]
} }

View File

@@ -361,15 +361,10 @@ mod tests {
_index: InterruptIndex, _index: InterruptIndex,
_config: InterruptSourceConfig, _config: InterruptSourceConfig,
_masked: bool, _masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> { ) -> result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap()) Some(self.event_fd.try_clone().unwrap())
} }

View File

@@ -2,27 +2,19 @@
// 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 LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
use std::sync::{ use std::sync::{Arc, Barrier};
atomic::{AtomicBool, Ordering},
Arc, Barrier,
};
use std::thread;
use vm_device::BusDevice; use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
/// A i8042 PS/2 controller that emulates just enough to shutdown the machine. /// A i8042 PS/2 controller that emulates just enough to shutdown the machine.
pub struct I8042Device { pub struct I8042Device {
reset_evt: EventFd, reset_evt: EventFd,
vcpus_kill_signalled: Arc<AtomicBool>,
} }
impl I8042Device { impl I8042Device {
/// Constructs a i8042 device that will signal the given event when the guest requests it. /// Constructs a i8042 device that will signal the given event when the guest requests it.
pub fn new(reset_evt: EventFd, vcpus_kill_signalled: Arc<AtomicBool>) -> I8042Device { pub fn new(reset_evt: EventFd) -> I8042Device {
I8042Device { I8042Device { reset_evt }
reset_evt,
vcpus_kill_signalled,
}
} }
} }
@@ -46,13 +38,6 @@ impl BusDevice for I8042Device {
if let Err(e) = self.reset_evt.write(1) { if let Err(e) = self.reset_evt.write(1) {
error!("Error triggering i8042 reset event: {}", e); error!("Error triggering i8042 reset event: {}", e);
} }
// Spin until we are sure the reset_evt has been handled and that when
// we return from the KVM_RUN we will exit rather than re-enter the guest.
while !self.vcpus_kill_signalled.load(Ordering::SeqCst) {
// This is more effective than thread::yield_now() at
// avoiding a priority inversion with the VMM thread
thread::sleep(std::time::Duration::from_millis(1));
}
} }
None None

View File

@@ -413,15 +413,10 @@ mod tests {
_index: InterruptIndex, _index: InterruptIndex,
_config: InterruptSourceConfig, _config: InterruptSourceConfig,
_masked: bool, _masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> { ) -> result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap()) Some(self.event_fd.try_clone().unwrap())
} }

View File

@@ -365,13 +365,9 @@ mod tests {
_index: InterruptIndex, _index: InterruptIndex,
_config: InterruptSourceConfig, _config: InterruptSourceConfig,
_masked: bool, _masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> { ) -> result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap()) Some(self.event_fd.try_clone().unwrap())
} }

View File

@@ -485,13 +485,9 @@ mod tests {
_index: InterruptIndex, _index: InterruptIndex,
_config: InterruptSourceConfig, _config: InterruptSourceConfig,
_masked: bool, _masked: bool,
_set_gsi: bool,
) -> result::Result<(), std::io::Error> { ) -> result::Result<(), std::io::Error> {
Ok(()) Ok(())
} }
fn set_gsi(&self) -> result::Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap()) Some(self.event_fd.try_clone().unwrap())
} }

View File

@@ -10,8 +10,6 @@
#[macro_use] #[macro_use]
extern crate bitflags; extern crate bitflags;
#[macro_use] #[macro_use]
extern crate event_monitor;
#[macro_use]
extern crate log; extern crate log;
pub mod acpi; pub mod acpi;
@@ -21,11 +19,9 @@ pub mod interrupt_controller;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
pub mod ioapic; pub mod ioapic;
pub mod legacy; pub mod legacy;
pub mod pvpanic;
pub mod tpm; pub mod tpm;
pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice}; pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice};
pub use self::pvpanic::{PvPanicDevice, PVPANIC_DEVICE_MMIO_SIZE};
bitflags! { bitflags! {
pub struct AcpiNotificationFlags: u8 { pub struct AcpiNotificationFlags: u8 {

View File

@@ -1,272 +0,0 @@
// Copyright © 2023 Tencent Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
use anyhow::anyhow;
use pci::{
BarReprogrammingParams, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType,
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
PCI_CONFIGURATION_ID,
};
use std::any::Any;
use std::result;
use std::sync::{Arc, Barrier, Mutex};
use thiserror::Error;
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::{BusDevice, Resource};
use vm_memory::{Address, GuestAddress};
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable, VersionMapped,
};
const PVPANIC_VENDOR_ID: u16 = 0x1b36;
const PVPANIC_DEVICE_ID: u16 = 0x0011;
pub const PVPANIC_DEVICE_MMIO_SIZE: u64 = 0x2;
const PVPANIC_PANICKED: u8 = 1 << 0;
const PVPANIC_CRASH_LOADED: u8 = 1 << 1;
#[derive(Debug, Error)]
pub enum PvPanicError {
#[error("Failed creating PvPanicDevice: {0}")]
CreatePvPanicDevice(#[source] anyhow::Error),
#[error("Failed to retrieve PciConfigurationState: {0}")]
RetrievePciConfigurationState(#[source] anyhow::Error),
}
#[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum PvPanicSubclass {
Other = 0x80,
}
impl PciSubclass for PvPanicSubclass {
fn get_register_value(&self) -> u8 {
*self as u8
}
}
/// A device for handling guest panic event
pub struct PvPanicDevice {
id: String,
events: u8,
// PCI configuration registers.
configuration: PciConfiguration,
bar_regions: Vec<PciBarConfiguration>,
}
#[derive(Versionize)]
pub struct PvPanicDeviceState {
events: u8,
}
impl VersionMapped for PvPanicDeviceState {}
impl PvPanicDevice {
pub fn new(id: String, snapshot: Option<Snapshot>) -> Result<Self, PvPanicError> {
let pci_configuration_state =
vm_migration::versioned_state_from_id(snapshot.as_ref(), PCI_CONFIGURATION_ID)
.map_err(|e| {
PvPanicError::RetrievePciConfigurationState(anyhow!(
"Failed to get PciConfigurationState from Snapshot: {}",
e
))
})?;
let mut configuration = PciConfiguration::new(
PVPANIC_VENDOR_ID,
PVPANIC_DEVICE_ID,
0x1, // modern pci devices
PciClassCode::BaseSystemPeripheral,
&PvPanicSubclass::Other,
None,
PciHeaderType::Device,
0,
0,
None,
pci_configuration_state,
);
let command: [u8; 2] = [0x03, 0x01];
configuration.write_config_register(1, 0, &command);
let state: Option<PvPanicDeviceState> = snapshot
.as_ref()
.map(|s| s.to_versioned_state())
.transpose()
.map_err(|e| {
PvPanicError::CreatePvPanicDevice(anyhow!(
"Failed to get PvPanicDeviceState from Snapshot: {}",
e
))
})?;
let events = if let Some(state) = state {
state.events
} else {
PVPANIC_PANICKED | PVPANIC_CRASH_LOADED
};
let pvpanic_device = PvPanicDevice {
id,
events,
configuration,
bar_regions: vec![],
};
Ok(pvpanic_device)
}
pub fn event_to_string(&self, event: u8) -> String {
if event == PVPANIC_PANICKED {
"panic".to_string()
} else if event == PVPANIC_CRASH_LOADED {
"crash_loaded".to_string()
} else {
"unknown_event".to_string()
}
}
fn state(&self) -> PvPanicDeviceState {
PvPanicDeviceState {
events: self.events,
}
}
pub fn config_bar_addr(&self) -> u64 {
self.configuration.get_bar_addr(0)
}
}
impl BusDevice for PvPanicDevice {
fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) {
self.read_bar(base, offset, data)
}
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
let event = self.event_to_string(data[0]);
info!("pvpanic got guest event {}", event);
event!("guest", "panic", "event", &event);
None
}
}
impl PciDevice for PvPanicDevice {
fn write_config_register(
&mut self,
reg_idx: usize,
offset: u64,
data: &[u8],
) -> Option<Arc<Barrier>> {
self.configuration
.write_config_register(reg_idx, offset, data);
None
}
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
self.configuration.read_reg(reg_idx)
}
fn detect_bar_reprogramming(
&mut self,
reg_idx: usize,
data: &[u8],
) -> Option<BarReprogrammingParams> {
self.configuration.detect_bar_reprogramming(reg_idx, data)
}
fn allocate_bars(
&mut self,
allocator: &Arc<Mutex<SystemAllocator>>,
_mmio_allocator: &mut AddressAllocator,
resources: Option<Vec<Resource>>,
) -> std::result::Result<Vec<PciBarConfiguration>, PciDeviceError> {
let mut bars = Vec::new();
let region_type = PciBarRegionType::Memory32BitRegion;
let bar_id = 0;
let region_size = PVPANIC_DEVICE_MMIO_SIZE;
let restoring = resources.is_some();
let bar_addr = allocator
.lock()
.unwrap()
.allocate_mmio_hole_addresses(None, region_size, None)
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
let bar = PciBarConfiguration::default()
.set_index(bar_id as usize)
.set_address(bar_addr.raw_value())
.set_size(region_size)
.set_region_type(region_type)
.set_prefetchable(PciBarPrefetchable::NotPrefetchable);
debug!("pvpanic bar address 0x{:x}", bar_addr.0);
if !restoring {
self.configuration
.add_pci_bar(&bar)
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
}
bars.push(bar);
self.bar_regions = bars.clone();
Ok(bars)
}
fn free_bars(
&mut self,
allocator: &mut SystemAllocator,
_mmio_allocator: &mut AddressAllocator,
) -> std::result::Result<(), PciDeviceError> {
for bar in self.bar_regions.drain(..) {
allocator.free_mmio_hole_addresses(GuestAddress(bar.addr()), bar.size());
}
Ok(())
}
fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), std::io::Error> {
for bar in self.bar_regions.iter_mut() {
if bar.addr() == old_base {
*bar = bar.set_address(new_base);
}
}
Ok(())
}
fn read_bar(&mut self, _base: u64, _offset: u64, data: &mut [u8]) {
data[0] = self.events;
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
fn id(&self) -> Option<String> {
Some(self.id.clone())
}
}
impl Pausable for PvPanicDevice {}
impl Snapshottable for PvPanicDevice {
fn id(&self) -> String {
self.id.clone()
}
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
let mut snapshot = Snapshot::new_from_versioned_state(&self.state())?;
// Snapshot PciConfiguration
snapshot.add_snapshot(self.configuration.id(), self.configuration.snapshot()?);
Ok(snapshot)
}
}
impl Transportable for PvPanicDevice {}
impl Migratable for PvPanicDevice {}

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,18 +65,18 @@ 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 |
| ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ | | ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ |
@@ -115,10 +110,10 @@ The Cloud Hypervisor API exposes the following actions through its endpoints:
* The `vmcoredump` action is available exclusively for the `x86_64` * The `vmcoredump` action is available exclusively for the `x86_64`
architecture and can be executed only when the `guest_debug` feature is architecture and can be executed only when the `guest_debug` feature is
enabled. Without this feature, the corresponding [REST API](#rest-api) or enabled. Without this feature, the corresponding REST API endpoint is not
[D-Bus API](#d-bus-api) endpoints are not available. available.
#### REST API Examples ### 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 +129,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 +157,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
}' }'
``` ```
##### Boot a Virtual Machine #### Boot a Virtual Machine
Once the VM is created, we can boot it: Once the VM is created, we can boot it:
@@ -172,7 +167,7 @@ Once the VM is created, we can boot it:
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot' 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 +179,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 +189,7 @@ We can reboot a VM that's already booted:
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot' 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 +199,6 @@ Once booted, we can shut a VM down from the REST API:
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown' 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,26 +206,22 @@ the Cloud Hypervisor binary, i.e. it can not be used for controlling the VMM or
the launched VM once they're up and running. 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
@@ -285,11 +232,7 @@ The REST API is processed by an HTTP thread using the
crate. As with the CLI, the HTTP requests eventually get translated into 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 +243,11 @@ As a summary, the REST API, the D-Bus API and the CLI are essentially frontends
| +------------------+ | | +------------------+ |
| | +------------------------+ | | +------------------------+
| | | | | | | |
+------------+ | +----------+ | | | +------------+ | | | |
| | | D-Bus API | | | | +--------------+ | | | | | | +--------------+ |
| User +---------+----------->+ zbus +--------------+------> | Internal API | | | User +---------+ +------> | Internal API | |
| | | | | | | +--------------+ | | | | | | +--------------+ |
+------------+ | +----------+ | | | +------------+ | | | |
| | | | | | | |
| | +------------------------+ | | +------------------------+
| +----------+ | VMM | +----------+ | VMM
@@ -319,23 +262,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.

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

@@ -5,7 +5,6 @@ authors = ["The Cloud Hypervisor Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
flume = "0.10.14"
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.95"

View File

@@ -7,11 +7,33 @@ use serde::Serialize;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io; use std::io::Write;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
static mut MONITOR: Option<MonitorHandle> = None; static mut MONITOR: Option<(File, Instant)> = None;
/// This function must only be called once from the main process before any threads
/// are created to avoid race conditions
pub fn set_monitor(file: File) -> Result<(), std::io::Error> {
// SAFETY: there is only one caller of this function, so MONITOR is written to only once
assert!(unsafe { MONITOR.is_none() });
let fd = file.as_raw_fd();
// SAFETY: FFI call to configure the fd
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
libc::fcntl(fd, libc::F_SETFL, flags)
};
if ret < 0 {
return Err(std::io::Error::last_os_error());
}
// SAFETY: MONITOR is None. Nobody else can hold a reference to it.
unsafe {
MONITOR = Some((file, Instant::now()));
};
Ok(())
}
#[derive(Serialize)] #[derive(Serialize)]
struct Event<'a> { struct Event<'a> {
@@ -21,71 +43,19 @@ struct Event<'a> {
properties: Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>, properties: Option<&'a HashMap<Cow<'a, str>, Cow<'a, str>>>,
} }
pub struct Monitor {
pub rx: flume::Receiver<String>,
pub file: File,
}
struct MonitorHandle {
tx: flume::Sender<String>,
start: Instant,
}
fn set_file_nonblocking(file: &File) -> io::Result<()> {
let fd = file.as_raw_fd();
// SAFETY: FFI call to configure the fd
let ret = unsafe {
let mut flags = libc::fcntl(fd, libc::F_GETFL);
flags |= libc::O_NONBLOCK;
libc::fcntl(fd, libc::F_SETFL, flags)
};
if ret < 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
/// This function must only be called once from the main thread before any threads
/// are created to avoid race conditions.
pub fn set_monitor(file: File) -> io::Result<Monitor> {
// SAFETY: there is only one caller of this function, so MONITOR is written to only once
assert!(unsafe { MONITOR.is_none() });
set_file_nonblocking(&file)?;
let (tx, rx) = flume::unbounded();
let monitor = Monitor { rx, file };
// SAFETY: MONITOR is None. Nobody else can hold a reference to it.
unsafe {
MONITOR = Some(MonitorHandle {
tx,
start: Instant::now(),
});
};
Ok(monitor)
}
pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) { pub fn event_log(source: &str, event: &str, properties: Option<&HashMap<Cow<str>, Cow<str>>>) {
// SAFETY: `MONITOR` is always in a valid state (None or Some), because it // SAFETY: MONITOR is always in a valid state (None or Some).
// is set only once before any threads are spawned, and it's not mutated if let Some((file, start)) = unsafe { MONITOR.as_ref() } {
// afterwards. This function only creates immutable references to `MONITOR`. let e = Event {
// Because `MONITOR.tx` is `Sync`, it's safe to share `MONITOR` across timestamp: start.elapsed(),
// threads, making this function thread-safe.
if let Some(monitor_handle) = unsafe { MONITOR.as_ref() } {
let event = Event {
timestamp: monitor_handle.start.elapsed(),
source, source,
event, event,
properties, properties,
}; };
serde_json::to_writer_pretty(file, &e).ok();
if let Ok(event) = serde_json::to_string_pretty(&event) { let mut file = file;
monitor_handle.tx.send(event).ok(); file.write_all(b"\n\n").ok();
}
} }
} }
@@ -109,4 +79,5 @@ macro_rules! event {
$crate::event_log($source, $event, Some(&properties)) $crate::event_log($source, $event, Some(&properties))
} }
}; };
} }

435
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#0b892e2c2053c4ecfac8d9e5a52babae75114702"
dependencies = [ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.72" version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]] [[package]]
name = "api_client" name = "api_client"
@@ -85,12 +85,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f" checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "bincode" name = "bincode"
version = "1.3.3" version = "1.3.3"
@@ -107,39 +101,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "block_util"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
[[package]]
name = "block"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"byteorder",
"crc32c",
"io-uring", "io-uring",
"libc", "libc",
"log", "log",
"remain", "qcow",
"smallvec", "smallvec",
"thiserror", "thiserror",
"uuid",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
"virtio-bindings", "vhdx",
"virtio-bindings 0.2.0",
"virtio-queue", "virtio-queue",
"vm-memory", "vm-memory",
"vm-virtio", "vm-virtio",
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "bumpalo"
version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.4.3"
@@ -148,12 +128,11 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.82" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc",
] ]
[[package]] [[package]]
@@ -164,7 +143,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]] [[package]]
name = "cloud-hypervisor" name = "cloud-hypervisor"
version = "33.0.0" version = "30.0.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"api_client", "api_client",
@@ -190,7 +169,7 @@ dependencies = [
name = "cloud-hypervisor-fuzz" name = "cloud-hypervisor-fuzz"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"block", "block_util",
"cloud-hypervisor", "cloud-hypervisor",
"devices", "devices",
"epoll", "epoll",
@@ -200,7 +179,9 @@ dependencies = [
"micro_http", "micro_http",
"net_util", "net_util",
"once_cell", "once_cell",
"qcow",
"seccompiler", "seccompiler",
"vhdx",
"virtio-devices", "virtio-devices",
"virtio-queue", "virtio-queue",
"vm-device", "vm-device",
@@ -212,9 +193,9 @@ dependencies = [
[[package]] [[package]]
name = "crc32c" name = "crc32c"
version = "0.6.4" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8f48d60e5b4d2c53d5c2b1d8a58c849a70ae5e5509b08a48d047e3b65714a74" checksum = "3dfea2db42e9927a3845fb268a10a72faed6d416065f77873f05e411457c363e"
dependencies = [ dependencies = [
"rustc_version", "rustc_version",
] ]
@@ -227,9 +208,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.20.3" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"darling_macro", "darling_macro",
@@ -237,27 +218,27 @@ dependencies = [
[[package]] [[package]]
name = "darling_core" name = "darling_core"
version = "0.20.3" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"
dependencies = [ dependencies = [
"fnv", "fnv",
"ident_case", "ident_case",
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.23", "syn 1.0.109",
] ]
[[package]] [[package]]
name = "darling_macro" name = "darling_macro"
version = "0.20.3" version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.23", "syn 1.0.109",
] ]
[[package]] [[package]]
@@ -267,18 +248,15 @@ dependencies = [
"acpi_tables", "acpi_tables",
"anyhow", "anyhow",
"arch", "arch",
"bitflags 2.3.3", "bitflags",
"byteorder", "byteorder",
"event_monitor",
"hypervisor", "hypervisor",
"libc", "libc",
"log", "log",
"pci",
"thiserror", "thiserror",
"tpm", "tpm",
"versionize", "versionize",
"versionize_derive", "versionize_derive",
"vm-allocator",
"vm-device", "vm-device",
"vm-memory", "vm-memory",
"vm-migration", "vm-migration",
@@ -287,11 +265,11 @@ dependencies = [
[[package]] [[package]]
name = "epoll" name = "epoll"
version = "4.3.3" 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 = "74351c3392ea1ff6cd2628e0042d268ac2371cb613252ff383b6dfa50d22fa79" checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags",
"libc", "libc",
] ]
@@ -299,7 +277,6 @@ dependencies = [
name = "event_monitor" name = "event_monitor"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"flume",
"libc", "libc",
"serde", "serde",
"serde_json", "serde_json",
@@ -311,48 +288,21 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "flume"
version = "0.10.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
dependencies = [
"futures-core",
"futures-sink",
"nanorand",
"pin-project",
"spin",
]
[[package]] [[package]]
name = "fnv" name = "fnv"
version = "1.0.7" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "futures-core"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-sink"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
[[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",
"js-sys",
"libc", "libc",
"wasi", "wasi",
"wasm-bindgen",
] ]
[[package]] [[package]]
@@ -361,6 +311,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"byteorder", "byteorder",
"iced-x86",
"kvm-bindings", "kvm-bindings",
"kvm-ioctls", "kvm-ioctls",
"libc", "libc",
@@ -373,6 +324,15 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "iced-x86"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
dependencies = [
"lazy_static",
]
[[package]] [[package]]
name = "ident_case" name = "ident_case"
version = "1.0.1" version = "1.0.1"
@@ -381,19 +341,19 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]] [[package]]
name = "io-uring" name = "io-uring"
version = "0.6.0" 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 = "8b7b36074613a723279637061b40db993208908a94f10ccb14436ce735bc0f57" checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
"libc", "libc",
] ]
[[package]] [[package]]
name = "itoa" name = "itoa"
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 = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]] [[package]]
name = "jobserver" name = "jobserver"
@@ -404,15 +364,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "js-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
dependencies = [
"wasm-bindgen",
]
[[package]] [[package]]
name = "kvm-bindings" name = "kvm-bindings"
version = "0.6.0" version = "0.6.0"
@@ -435,10 +386,16 @@ dependencies = [
] ]
[[package]] [[package]]
name = "libc" name = "lazy_static"
version = "0.2.147" version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -453,28 +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]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[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"
@@ -485,15 +435,6 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "nanorand"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
dependencies = [
"getrandom",
]
[[package]] [[package]]
name = "net_gen" name = "net_gen"
version = "0.1.0" version = "0.1.0"
@@ -515,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",
@@ -524,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"
@@ -555,40 +496,31 @@ dependencies = [
"vmm-sys-util", "vmm-sys-util",
] ]
[[package]]
name = "pin-project"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.23",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.66" version = "1.0.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "qcow"
version = "0.1.0"
dependencies = [
"byteorder",
"libc",
"log",
"remain",
"vmm-sys-util",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.32" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -604,13 +536,13 @@ dependencies = [
[[package]] [[package]]
name = "remain" name = "remain"
version = "0.2.11" 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 = "bce3a7139d2ee67d07538ee5dba997364fbc243e7e7143e96eb830c74bfaa082" checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.23", "syn 2.0.4",
] ]
[[package]] [[package]]
@@ -624,15 +556,9 @@ dependencies = [
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.15" version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "seccompiler" name = "seccompiler"
@@ -645,35 +571,35 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.18" version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.168" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d614f89548720367ded108b3c843be93f3a341e22d5674ca0dd5cd57f34926af" checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.168" version = "1.0.159"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fe589678c688e44177da4f27152ee2d190757271dc7f1d5b6b9f68d869d641" checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.23", "syn 2.0.4",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.104" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@@ -682,9 +608,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_with" name = "serde_with"
version = "3.2.0" version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1402f54f9a3b9e2efe71c1cea24e648acce55887983553eeb858cf3115acfd49" checksum = "331bb8c3bf9b92457ab7abecf07078c13f7d270ba490103e84e8b014490cd0b0"
dependencies = [ dependencies = [
"serde", "serde",
"serde_with_macros", "serde_with_macros",
@@ -692,14 +618,14 @@ dependencies = [
[[package]] [[package]]
name = "serde_with_macros" name = "serde_with_macros"
version = "3.2.0" version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9197f1ad0e3c173a0222d3c4404fb04c3afe87e962bcb327af73e8301fa203c7" checksum = "859011bddcc11f289f07f467cc1fe01c7a941daa4d8f6c40d4d1c92eb6d9319c"
dependencies = [ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.23", "syn 1.0.109",
] ]
[[package]] [[package]]
@@ -708,9 +634,9 @@ version = "0.1.0"
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.17" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
@@ -727,18 +653,9 @@ dependencies = [
[[package]] [[package]]
name = "smallvec" name = "smallvec"
version = "1.11.0" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
@@ -759,9 +676,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.23" version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59fb7d6d8281a51045d62b8eb3a7d1ce347b76f312af50cd3dc0af39c87c1737" checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -770,22 +687,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.44" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.44" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.23", "syn 2.0.4",
] ]
[[package]] [[package]]
@@ -814,15 +731,15 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.11" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.4.1" 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 = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
dependencies = [ dependencies = [
"getrandom", "getrandom",
] ]
@@ -857,7 +774,7 @@ dependencies = [
[[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",
] ]
@@ -865,7 +782,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",
@@ -881,9 +798,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",
@@ -896,12 +813,25 @@ dependencies = [
] ]
[[package]] [[package]]
name = "vhost" name = "vhdx"
version = "0.7.0" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84f81f436bca4541f4d33172e1202882c9d437db34ed17fc6d84c8ff2bde21f5"
dependencies = [ dependencies = [
"bitflags 1.3.2", "byteorder",
"crc32c",
"libc",
"log",
"remain",
"thiserror",
"uuid",
]
[[package]]
name = "vhost"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
dependencies = [
"bitflags",
"libc", "libc",
"vm-memory", "vm-memory",
"vmm-sys-util", "vmm-sys-util",
@@ -909,9 +839,15 @@ dependencies = [
[[package]] [[package]]
name = "virtio-bindings" name = "virtio-bindings"
version = "0.2.1" version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c18d7b74098a946470ea265b5bacbbf877abc3373021388454de0d47735a5b98" checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
[[package]]
name = "virtio-bindings"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9084faf91b9aa9676ae2cac8f1432df2839d9566e6f19f29dbc13a8b831dff"
[[package]] [[package]]
name = "virtio-devices" name = "virtio-devices"
@@ -919,10 +855,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
"block", "block_util",
"byteorder", "byteorder",
"epoll", "epoll",
"event_monitor", "event_monitor",
"io-uring",
"libc", "libc",
"log", "log",
"net_gen", "net_gen",
@@ -937,7 +874,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",
@@ -949,12 +886,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",
] ]
@@ -988,9 +925,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",
@@ -1027,8 +964,8 @@ dependencies = [
"anyhow", "anyhow",
"arc-swap", "arc-swap",
"arch", "arch",
"bitflags 2.3.3", "bitflags",
"block", "block_util",
"devices", "devices",
"epoll", "epoll",
"event_monitor", "event_monitor",
@@ -1041,6 +978,7 @@ dependencies = [
"once_cell", "once_cell",
"option_parser", "option_parser",
"pci", "pci",
"qcow",
"seccompiler", "seccompiler",
"serde", "serde",
"serde_json", "serde_json",
@@ -1053,6 +991,7 @@ dependencies = [
"versionize_derive", "versionize_derive",
"vfio-ioctls", "vfio-ioctls",
"vfio_user", "vfio_user",
"vhdx",
"virtio-devices", "virtio-devices",
"virtio-queue", "virtio-queue",
"vm-allocator", "vm-allocator",
@@ -1070,7 +1009,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",
@@ -1082,60 +1021,6 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.23",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.23",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@@ -1160,9 +1045,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.6.3" version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3b9c234616391070b0b173963ebc65a9195068e7ed3731c6edac2ec45ebe106" checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"zerocopy-derive", "zerocopy-derive",
@@ -1170,11 +1055,11 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.6.3" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f7f3a471f98d0a61c34322fbbfd10c384b07687f680d4119813713f72308d91" checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.23", "syn 1.0.109",
] ]

View File

@@ -9,21 +9,23 @@ edition = "2021"
cargo-fuzz = true cargo-fuzz = true
[dependencies] [dependencies]
block = { path = "../block" } 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.141"
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" }
seccompiler = "0.3.0" seccompiler = "0.3.0"
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

@@ -8,7 +8,7 @@
#![no_main] #![no_main]
use block::{async_io::DiskFile, raw_sync::RawFileDiskSync}; use block_util::{async_io::DiskFile, raw_sync::RawFileDiskSync};
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use seccompiler::SeccompAction; use seccompiler::SeccompAction;
use std::ffi; use std::ffi;

View File

@@ -6,8 +6,6 @@
use devices::legacy::Cmos; use devices::legacy::Cmos;
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use vm_device::BusDevice; use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
@@ -27,7 +25,6 @@ fuzz_target!(|bytes| {
u64::from_le_bytes(below_4g), u64::from_le_bytes(below_4g),
u64::from_le_bytes(above_4g), u64::from_le_bytes(above_4g),
EventFd::new(EFD_NONBLOCK).unwrap(), EventFd::new(EFD_NONBLOCK).unwrap(),
None,
); );
let mut i = 16; let mut i = 16;

View File

@@ -4,7 +4,7 @@
#![no_main] #![no_main]
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use block::qcow::{QcowFile, RawFile}; use qcow::{QcowFile, RawFile};
use std::ffi; use std::ffi;
use std::fs::File; use std::fs::File;
use std::io::{self, Cursor, Read, Seek, SeekFrom, Write}; use std::io::{self, Cursor, Read, Seek, SeekFrom, Write};

View File

@@ -59,13 +59,9 @@ impl InterruptSourceGroup for TestInterrupt {
_index: InterruptIndex, _index: InterruptIndex,
_config: InterruptSourceConfig, _config: InterruptSourceConfig,
_masked: bool, _masked: bool,
_set_gsi: bool,
) -> Result<(), std::io::Error> { ) -> Result<(), std::io::Error> {
Ok(()) Ok(())
} }
fn set_gsi(&self) -> Result<(), std::io::Error> {
Ok(())
}
fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> { fn notifier(&self, _index: InterruptIndex) -> Option<EventFd> {
Some(self.event_fd.try_clone().unwrap()) Some(self.event_fd.try_clone().unwrap())
} }

View File

@@ -8,7 +8,7 @@ use std::ffi;
use std::fs::File; use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write}; use std::io::{self, Read, Seek, SeekFrom, Write};
use std::os::unix::io::{FromRawFd, RawFd}; use std::os::unix::io::{FromRawFd, RawFd};
use block::vhdx::Vhdx; use vhdx::vhdx::Vhdx;
// Populate the corpus directory with a test file: // Populate the corpus directory with a test file:
// truncate -s 16M /tmp/source // truncate -s 16M /tmp/source

View File

@@ -7,28 +7,27 @@ license = "Apache-2.0 OR BSD-3-Clause"
[features] [features]
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"] kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"]
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv", "iced-x86"] mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"]
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.39"
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.3.1", 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]
optional = true version = "1.18.0"
version = "1.19.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

@@ -239,36 +239,6 @@ impl<T: CpuStateManager> InstructionHandler<T> for Movzx_r64_rm16 {
movzx!(u64, u16); movzx!(u64, u16);
} }
pub struct Mov_moffs16_AX;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs16_AX {
movzx!(u16, u16);
}
pub struct Mov_AX_moffs16;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_AX_moffs16 {
movzx!(u16, u16);
}
pub struct Mov_moffs32_EAX;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs32_EAX {
movzx!(u32, u32);
}
pub struct Mov_EAX_moffs32;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_EAX_moffs32 {
movzx!(u32, u32);
}
pub struct Mov_moffs64_RAX;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_moffs64_RAX {
movzx!(u64, u64);
}
pub struct Mov_RAX_moffs64;
impl<T: CpuStateManager> InstructionHandler<T> for Mov_RAX_moffs64 {
movzx!(u64, u64);
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#![allow(unused_mut)] #![allow(unused_mut)]
@@ -647,123 +617,4 @@ mod tests {
.unwrap(); .unwrap();
assert_eq!(eax, value as u64); assert_eq!(eax, value as u64);
} }
#[test]
// movabs ax, ds:0x1337
// movabs eax, ds:0x1337
// movabs rax, ds:0x1337
fn test_mov_memoff_ax() {
let test_inputs: [(Register, &[u8]); 3] = [
(Register::AX, &[0x66, 0xa1]),
(Register::EAX, &[0xa1]),
(Register::RAX, &[0x48, 0xa1]),
];
// Constructs the instruction with the provided inputs and emulates it.
fn helper(register: Register, instruction_prefix: &[u8]) {
let mem_addr: u64 = 0x1337;
let mem_value: u64 = 0x13371337deadbeef;
let ip: u64 = 0x1000;
let cpu_id = 0;
let mut instruction_bytes = Vec::new();
// instruction prefix with specified register
instruction_bytes.extend(instruction_prefix);
// 64-bit memory operand
instruction_bytes.extend([
mem_addr.to_le_bytes()[0],
mem_addr.to_le_bytes()[1],
0,
0,
0,
0,
0,
0,
]);
let memory: [u8; 8] = mem_value.to_le_bytes();
let mut vmm = MockVmm::new(ip, vec![], Some((mem_addr, &memory)));
assert!(vmm.emulate_first_insn(cpu_id, &instruction_bytes).is_ok());
let ax: u64 = vmm.cpu_state(cpu_id).unwrap().read_reg(register).unwrap();
match register {
Register::AX => {
assert_eq!(ax as u16, mem_value as u16);
}
Register::EAX => {
assert_eq!(ax as u32, mem_value as u32);
}
Register::RAX => {
assert_eq!(ax, mem_value);
}
_ => panic!(),
}
}
for (register, instruction_prefix) in test_inputs {
helper(register, instruction_prefix)
}
}
#[test]
// movabs ds:0x1337, ax
// movabs ds:0x1337, eax
// movabs ds:0x1337, rax
fn test_mov_ax_memoff() {
let test_inputs: [(Register, &[u8]); 3] = [
(Register::AX, &[0x66, 0xa3]),
(Register::EAX, &[0xa3]),
(Register::RAX, &[0x48, 0xa3]),
];
// Constructs the instruction with the provided inputs and emulates it.
fn helper(register: Register, instruction_prefix: &[u8]) {
let mem_addr: u64 = 0x1337;
let ax: u64 = 0x13371337deadbeef;
let ip: u64 = 0x1000;
let cpu_id = 0;
let mut instruction_bytes = Vec::new();
// instruction prefix with specified register
instruction_bytes.extend(instruction_prefix);
// 64-bit memory operand
instruction_bytes.extend([
mem_addr.to_le_bytes()[0],
mem_addr.to_le_bytes()[1],
0,
0,
0,
0,
0,
0,
]);
let mut vmm = MockVmm::new(ip, vec![(Register::RAX, ax)], None);
assert!(vmm.emulate_first_insn(cpu_id, &instruction_bytes).is_ok());
match register {
Register::AX => {
let mut memory: [u8; 2] = [0; 2];
vmm.read_memory(mem_addr, &mut memory).unwrap();
assert_eq!(u16::from_le_bytes(memory), ax as u16);
}
Register::EAX => {
let mut memory: [u8; 4] = [0; 4];
vmm.read_memory(mem_addr, &mut memory).unwrap();
assert_eq!(u32::from_le_bytes(memory), ax as u32);
}
Register::RAX => {
let mut memory: [u8; 8] = [0; 8];
vmm.read_memory(mem_addr, &mut memory).unwrap();
assert_eq!(u64::from_le_bytes(memory), ax);
}
_ => panic!(),
}
}
for (register, instruction_prefix) in test_inputs {
helper(register, instruction_prefix)
}
}
} }

View File

@@ -524,13 +524,6 @@ impl<'a, T: CpuStateManager> Emulator<'a, T> {
(mov, Movzx_r64_rm8), (mov, Movzx_r64_rm8),
(mov, Movzx_r32_rm16), (mov, Movzx_r32_rm16),
(mov, Movzx_r64_rm16), (mov, Movzx_r64_rm16),
// MOV MOFFS
(mov, Mov_moffs16_AX),
(mov, Mov_AX_moffs16),
(mov, Mov_moffs32_EAX),
(mov, Mov_EAX_moffs32),
(mov, Mov_moffs64_RAX),
(mov, Mov_RAX_moffs64),
// MOVS // MOVS
(movs, Movsd_m32_m32), (movs, Movsd_m32_m32),
(movs, Movsw_m16_m16), (movs, Movsw_m16_m16),

View File

@@ -11,7 +11,6 @@
// Copyright © 2020, Microsoft Corporation // Copyright © 2020, Microsoft Corporation
// //
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
pub mod emulator; pub mod emulator;
pub mod gdt; pub mod gdt;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
@@ -27,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),
} }
/// ///
@@ -145,27 +136,4 @@ pub trait Hypervisor: Send + Sync {
/// Get maximum number of vCPUs /// Get maximum number of vCPUs
fn get_max_vcpus(&self) -> u32; 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

@@ -36,7 +36,7 @@ pub mod kvm;
#[cfg(all(feature = "mshv", target_arch = "x86_64"))] #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
pub mod mshv; pub mod mshv;
/// Hypervisor related module /// Hypevisor related module
mod hypervisor; mod hypervisor;
/// Vm related module /// Vm related module
@@ -49,8 +49,6 @@ mod cpu;
mod device; mod device;
pub use crate::hypervisor::{Hypervisor, HypervisorError}; 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;
#[cfg(all(feature = "kvm", target_arch = "aarch64"))] #[cfg(all(feature = "kvm", target_arch = "aarch64"))]

View File

@@ -38,7 +38,9 @@ use std::fs::File;
use std::os::unix::io::AsRawFd; use std::os::unix::io::AsRawFd;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry}; use crate::arch::x86::{
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
};
const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4; const DIRTY_BITMAP_CLEAR_DIRTY: u64 = 0x4;
const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8; const DIRTY_BITMAP_SET_DIRTY: u64 = 0x8;
@@ -312,7 +314,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Returns the vCPU general purpose registers. /// Returns the vCPU general purpose registers.
/// ///
fn get_regs(&self) -> cpu::Result<crate::arch::x86::StandardRegisters> { fn get_regs(&self) -> cpu::Result<StandardRegisters> {
Ok(self Ok(self
.fd .fd
.get_regs() .get_regs()
@@ -323,7 +325,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Sets the vCPU general purpose registers. /// Sets the vCPU general purpose registers.
/// ///
fn set_regs(&self, regs: &crate::arch::x86::StandardRegisters) -> cpu::Result<()> { fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
let regs = (*regs).into(); let regs = (*regs).into();
self.fd self.fd
.set_regs(&regs) .set_regs(&regs)
@@ -333,7 +335,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Returns the vCPU special registers. /// Returns the vCPU special registers.
/// ///
fn get_sregs(&self) -> cpu::Result<crate::arch::x86::SpecialRegisters> { fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
Ok(self Ok(self
.fd .fd
.get_sregs() .get_sregs()
@@ -344,7 +346,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Sets the vCPU special registers. /// Sets the vCPU special registers.
/// ///
fn set_sregs(&self, sregs: &crate::arch::x86::SpecialRegisters) -> cpu::Result<()> { fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
let sregs = (*sregs).into(); let sregs = (*sregs).into();
self.fd self.fd
.set_sregs(&sregs) .set_sregs(&sregs)
@@ -459,10 +461,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()))?;
@@ -508,10 +510,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()))?;
@@ -601,7 +603,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
/// ///
fn get_lapic(&self) -> cpu::Result<crate::arch::x86::LapicState> { fn get_lapic(&self) -> cpu::Result<LapicState> {
Ok(self Ok(self
.fd .fd
.get_lapic() .get_lapic()
@@ -612,7 +614,7 @@ impl cpu::Vcpu for MshvVcpu {
/// ///
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
/// ///
fn set_lapic(&self, lapic: &crate::arch::x86::LapicState) -> cpu::Result<()> { fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> {
let lapic: mshv_bindings::LapicState = (*lapic).clone().into(); let lapic: mshv_bindings::LapicState = (*lapic).clone().into();
self.fd self.fd
.set_lapic(&lapic) .set_lapic(&lapic)

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)]

View File

@@ -5,24 +5,24 @@ authors = ["The Chromium OS Authors"]
edition = "2021" edition = "2021"
[dependencies] [dependencies]
epoll = "4.3.3" epoll = "4.3.1"
getrandom = "0.2.10" getrandom = "0.2.8"
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" }
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.39"
versionize = "0.1.10" versionize = "0.1.10"
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.1"
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"
[dev-dependencies] [dev-dependencies]
once_cell = "1.18.0" 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.95"

View File

@@ -87,7 +87,7 @@ impl TxVirtio {
let result = unsafe { let result = unsafe {
libc::writev( libc::writev(
tap.as_raw_fd() as libc::c_int, tap.as_raw_fd() as libc::c_int,
iovecs.as_ptr(), iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int, iovecs.len() as libc::c_int,
) )
}; };
@@ -226,7 +226,7 @@ impl RxVirtio {
let result = unsafe { let result = unsafe {
libc::readv( libc::readv(
tap.as_raw_fd() as libc::c_int, tap.as_raw_fd() as libc::c_int,
iovecs.as_ptr(), iovecs.as_ptr() as *const libc::iovec,
iovecs.len() as libc::c_int, iovecs.len() as libc::c_int,
) )
}; };

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.39"
versionize = "0.1.10" versionize = "0.1.10"
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

@@ -205,15 +205,10 @@ impl MsiConfig {
idx as InterruptIndex, idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
state.cap.vector_masked(idx), state.cap.vector_masked(idx),
false,
) )
.map_err(Error::UpdateInterruptRoute)?; .map_err(Error::UpdateInterruptRoute)?;
} }
interrupt_source_group
.set_gsi()
.map_err(Error::EnableInterruptRoute)?;
interrupt_source_group interrupt_source_group
.enable() .enable()
.map_err(Error::EnableInterruptRoute)?; .map_err(Error::EnableInterruptRoute)?;
@@ -267,7 +262,6 @@ impl MsiConfig {
idx as InterruptIndex, idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
self.cap.vector_masked(idx), self.cap.vector_masked(idx),
true,
) { ) {
error!("Failed updating vector: {:?}", e); error!("Failed updating vector: {:?}", e);
} }

View File

@@ -107,7 +107,6 @@ impl MsixConfig {
idx as InterruptIndex, idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
state.masked, state.masked,
true,
) )
.map_err(Error::UpdateInterruptRoute)?; .map_err(Error::UpdateInterruptRoute)?;
@@ -183,7 +182,6 @@ impl MsixConfig {
idx as InterruptIndex, idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
table_entry.masked(), table_entry.masked(),
true,
) { ) {
error!("Failed updating vector: {:?}", e); error!("Failed updating vector: {:?}", e);
} }
@@ -322,7 +320,6 @@ impl MsixConfig {
index as InterruptIndex, index as InterruptIndex,
InterruptSourceConfig::MsiIrq(config), InterruptSourceConfig::MsiIrq(config),
table_entry.masked(), table_entry.masked(),
true,
) { ) {
error!("Failed updating vector: {:?}", e); error!("Failed updating vector: {:?}", e);
} }

View File

@@ -505,28 +505,24 @@ impl VfioCommon {
/// In case msix table offset is not page size aligned, we need do some fixup to achive it. /// 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. /// 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 { fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
if let Some(msix) = self.interrupt.msix.as_mut() { let msix = self.interrupt.msix.as_mut().unwrap();
let msix_cap = &mut msix.cap; let msix_cap = &mut msix.cap;
// Suppose table_bir equals to pba_bir here. Am I right? // Suppose table_bir equals to pba_bir here. Am I right?
let (table_offset, table_size) = msix_cap.table_range(); let (table_offset, table_size) = msix_cap.table_range();
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id { if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
return region_size; 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
} else {
// MSI-X not supported for this device
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(

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.95"
test_infra = { path = "../test_infra" } test_infra = { path = "../test_infra" }
thiserror = "1.0.40" thiserror = "1.0.39"
wait-timeout = "0.2.0" wait-timeout = "0.2.0"

View File

@@ -671,7 +671,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;
} }

16
qcow/Cargo.toml Normal file
View File

@@ -0,0 +1,16 @@
[package]
name = "qcow"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
license = "BSD-3-Clause"
[lib]
path = "src/qcow.rs"
[dependencies]
byteorder = "1.4.3"
libc = "0.2.139"
log = "0.4.17"
remain = "0.2.6"
vmm-sys-util = "0.11.0"

View File

@@ -2,45 +2,40 @@
// 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 LICENSE-BSD-3-Clause file. // found in the LICENSE-BSD-3-Clause file.
#[macro_use]
extern crate log;
mod qcow_raw_file; mod qcow_raw_file;
mod raw_file; mod raw_file;
mod refcount; mod refcount;
mod vec_cache; mod vec_cache;
use crate::qcow::{ use crate::qcow_raw_file::QcowRawFile;
qcow_raw_file::QcowRawFile, use crate::refcount::RefCount;
refcount::RefCount, use crate::vec_cache::{CacheMap, Cacheable, VecCache};
vec_cache::{CacheMap, Cacheable, VecCache},
};
use crate::BlockBackend;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use libc::{EINVAL, ENOSPC, ENOTSUP}; use libc::{EINVAL, ENOSPC, ENOTSUP};
use remain::sorted; use remain::sorted;
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use std::fs::OpenOptions;
use std::io::{self, Read, Seek, SeekFrom, Write}; use std::io::{self, Read, Seek, SeekFrom, Write};
use std::mem::size_of; use std::mem::size_of;
use std::str;
use vmm_sys_util::{ use vmm_sys_util::{
file_traits::FileSetLen, file_traits::FileSync, seek_hole::SeekHole, write_zeroes::PunchHole, file_traits::FileSetLen, file_traits::FileSync, seek_hole::SeekHole, write_zeroes::PunchHole,
write_zeroes::WriteZeroesAt, write_zeroes::WriteZeroesAt,
}; };
pub use crate::qcow::raw_file::RawFile; pub use crate::raw_file::RawFile;
#[sorted] #[sorted]
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {
BackingFileIo(io::Error), BackingFilesNotSupported,
BackingFileOpen(Box<crate::Error>),
BackingFileTooLong(usize),
CompressedBlocksNotSupported, CompressedBlocksNotSupported,
EvictingCache(io::Error), EvictingCache(io::Error),
FileTooBig(u64), FileTooBig(u64),
GettingFileSize(io::Error), GettingFileSize(io::Error),
GettingRefcount(refcount::Error), GettingRefcount(refcount::Error),
InvalidBackingFileName(str::Utf8Error),
InvalidClusterIndex, InvalidClusterIndex,
InvalidClusterSize, InvalidClusterSize,
InvalidIndex, InvalidIndex,
@@ -83,17 +78,12 @@ impl Display for Error {
#[sorted] #[sorted]
match self { match self {
BackingFileIo(e) => write!(f, "backing file io error: {}", e), BackingFilesNotSupported => write!(f, "backing files not supported"),
BackingFileOpen(e) => write!(f, "backing file open error: {}", *e),
BackingFileTooLong(len) => {
write!(f, "backing file name is too long: {} bytes over", len)
}
CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"), CompressedBlocksNotSupported => write!(f, "compressed blocks not supported"),
EvictingCache(e) => write!(f, "failed to evict cache: {e}"), EvictingCache(e) => write!(f, "failed to evict cache: {e}"),
FileTooBig(size) => write!(f, "file larger than max of {MAX_QCOW_FILE_SIZE}: {size}"), FileTooBig(size) => write!(f, "file larger than max of {MAX_QCOW_FILE_SIZE}: {size}"),
GettingFileSize(e) => write!(f, "failed to get file size: {e}"), GettingFileSize(e) => write!(f, "failed to get file size: {e}"),
GettingRefcount(e) => write!(f, "failed to get refcount: {e}"), GettingRefcount(e) => write!(f, "failed to get refcount: {e}"),
InvalidBackingFileName(e) => write!(f, "failed to parse filename: {}", e),
InvalidClusterIndex => write!(f, "invalid cluster index"), InvalidClusterIndex => write!(f, "invalid cluster index"),
InvalidClusterSize => write!(f, "invalid cluster size"), InvalidClusterSize => write!(f, "invalid cluster size"),
InvalidIndex => write!(f, "invalid index"), InvalidIndex => write!(f, "invalid index"),
@@ -163,14 +153,8 @@ const COMPRESSED_FLAG: u64 = 1 << 62;
const CLUSTER_USED_FLAG: u64 = 1 << 63; const CLUSTER_USED_FLAG: u64 = 1 << 63;
const COMPATIBLE_FEATURES_LAZY_REFCOUNTS: u64 = 1; const COMPATIBLE_FEATURES_LAZY_REFCOUNTS: u64 = 1;
// The format supports a "header extension area", that crosvm does not use.
const QCOW_EMPTY_HEADER_EXTENSION_SIZE: u32 = 8;
// Defined by the specification
const MAX_BACKING_FILE_SIZE: u32 = 1023;
/// Contains the information from the header of a qcow file. /// Contains the information from the header of a qcow file.
#[derive(Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub struct QcowHeader { pub struct QcowHeader {
pub magic: u32, pub magic: u32,
pub version: u32, pub version: u32,
@@ -197,9 +181,6 @@ pub struct QcowHeader {
pub autoclear_features: u64, pub autoclear_features: u64,
pub refcount_order: u32, pub refcount_order: u32,
pub header_size: u32, pub header_size: u32,
// Post-header entries
pub backing_file_path: Option<String>,
} }
impl QcowHeader { impl QcowHeader {
@@ -223,7 +204,7 @@ impl QcowHeader {
let version = read_u32_from_file(f)?; let version = read_u32_from_file(f)?;
let mut header = QcowHeader { Ok(QcowHeader {
magic, magic,
version, version,
backing_file_offset: read_u64_from_file(f)?, backing_file_offset: read_u64_from_file(f)?,
@@ -262,58 +243,24 @@ impl QcowHeader {
} else { } else {
read_u32_from_file(f)? read_u32_from_file(f)?
}, },
backing_file_path: None, })
};
if header.backing_file_size > MAX_BACKING_FILE_SIZE {
return Err(Error::BackingFileTooLong(header.backing_file_size as usize));
}
if header.backing_file_offset != 0 {
f.seek(SeekFrom::Start(header.backing_file_offset))
.map_err(Error::ReadingHeader)?;
let mut backing_file_name_bytes = vec![0u8; header.backing_file_size as usize];
f.read_exact(&mut backing_file_name_bytes)
.map_err(Error::ReadingHeader)?;
header.backing_file_path = Some(
String::from_utf8(backing_file_name_bytes)
.map_err(|err| Error::InvalidBackingFileName(err.utf8_error()))?,
);
}
Ok(header)
} }
pub fn create_for_size_and_path( /// Create a header for the given `size`.
version: u32, pub fn create_for_size(version: u32, size: u64) -> QcowHeader {
size: u64,
backing_file: Option<&str>,
) -> Result<QcowHeader> {
let header_size = if version == 2 {
V2_BARE_HEADER_SIZE
} else {
V3_BARE_HEADER_SIZE + QCOW_EMPTY_HEADER_EXTENSION_SIZE
};
let cluster_bits: u32 = DEFAULT_CLUSTER_BITS; let cluster_bits: u32 = DEFAULT_CLUSTER_BITS;
let cluster_size: u32 = 0x01 << cluster_bits; let cluster_size: u32 = 0x01 << cluster_bits;
let max_length: usize = (cluster_size - header_size) as usize;
if let Some(path) = backing_file {
if path.len() > max_length {
return Err(Error::BackingFileTooLong(path.len() - max_length));
}
}
// L2 blocks are always one cluster long. They contain cluster_size/sizeof(u64) addresses. // L2 blocks are always one cluster long. They contain cluster_size/sizeof(u64) addresses.
let entries_per_cluster: u32 = cluster_size / size_of::<u64>() as u32; let entries_per_cluster: u32 = cluster_size / size_of::<u64>() as u32;
let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32; let num_clusters: u32 = div_round_up_u64(size, u64::from(cluster_size)) as u32;
let num_l2_clusters: u32 = div_round_up_u32(num_clusters, entries_per_cluster); let num_l2_clusters: u32 = div_round_up_u32(num_clusters, entries_per_cluster);
let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, entries_per_cluster); let l1_clusters: u32 = div_round_up_u32(num_l2_clusters, entries_per_cluster);
let header_clusters = div_round_up_u32(size_of::<QcowHeader>() as u32, cluster_size); let header_clusters = div_round_up_u32(size_of::<QcowHeader>() as u32, cluster_size);
Ok(QcowHeader { QcowHeader {
magic: QCOW_MAGIC, magic: QCOW_MAGIC,
version, version,
backing_file_offset: (if backing_file.is_none() { backing_file_offset: 0,
0 backing_file_size: 0,
} else {
header_size
}) as u64,
backing_file_size: backing_file.map_or(0, |x| x.len()) as u32,
cluster_bits: DEFAULT_CLUSTER_BITS, cluster_bits: DEFAULT_CLUSTER_BITS,
size, size,
crypt_method: 0, crypt_method: 0,
@@ -342,9 +289,12 @@ impl QcowHeader {
compatible_features: 0, compatible_features: 0,
autoclear_features: 0, autoclear_features: 0,
refcount_order: DEFAULT_REFCOUNT_ORDER, refcount_order: DEFAULT_REFCOUNT_ORDER,
header_size, header_size: if version == 2 {
backing_file_path: backing_file.map(String::from), V2_BARE_HEADER_SIZE
}) } else {
V3_BARE_HEADER_SIZE
},
}
} }
/// Write the header to `file`. /// Write the header to `file`.
@@ -374,20 +324,11 @@ impl QcowHeader {
write_u32_to_file(file, self.refcount_table_clusters)?; write_u32_to_file(file, self.refcount_table_clusters)?;
write_u32_to_file(file, self.nb_snapshots)?; write_u32_to_file(file, self.nb_snapshots)?;
write_u64_to_file(file, self.snapshots_offset)?; write_u64_to_file(file, self.snapshots_offset)?;
write_u64_to_file(file, self.incompatible_features)?;
if self.version == 3 { write_u64_to_file(file, self.compatible_features)?;
write_u64_to_file(file, self.incompatible_features)?; write_u64_to_file(file, self.autoclear_features)?;
write_u64_to_file(file, self.compatible_features)?; write_u32_to_file(file, self.refcount_order)?;
write_u64_to_file(file, self.autoclear_features)?; write_u32_to_file(file, self.header_size)?;
write_u32_to_file(file, self.refcount_order)?;
write_u32_to_file(file, self.header_size)?;
write_u32_to_file(file, 0)?; // header extension type: end of header extension area
write_u32_to_file(file, 0)?; // length of header extension data: 0
}
if let Some(backing_file_path) = self.backing_file_path.as_ref() {
write!(file, "{}", backing_file_path).map_err(Error::WritingHeader)?;
}
// Set the file length by seeking and writing a zero to the last byte. This avoids needing // Set the file length by seeking and writing a zero to the last byte. This avoids needing
// a `File` instead of anything that implements seek as the `file` argument. // a `File` instead of anything that implements seek as the `file` argument.
@@ -421,8 +362,8 @@ fn max_refcount_clusters(refcount_order: u32, cluster_size: u32, num_clusters: u
/// # Example /// # Example
/// ///
/// ``` /// ```
/// # use block::qcow::{self, QcowFile, RawFile};
/// # use std::io::{Read, Seek, SeekFrom}; /// # use std::io::{Read, Seek, SeekFrom};
/// # use qcow::{self, QcowFile, RawFile};
/// # fn test(file: std::fs::File) -> std::io::Result<()> { /// # fn test(file: std::fs::File) -> std::io::Result<()> {
/// let mut raw_img = RawFile::new(file, false); /// let mut raw_img = RawFile::new(file, false);
/// let mut q = QcowFile::from(raw_img).expect("Can't open qcow file"); /// let mut q = QcowFile::from(raw_img).expect("Can't open qcow file");
@@ -432,7 +373,7 @@ fn max_refcount_clusters(refcount_order: u32, cluster_size: u32, num_clusters: u
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[derive(Debug)] #[derive(Clone, Debug)]
pub struct QcowFile { pub struct QcowFile {
raw_file: QcowRawFile, raw_file: QcowRawFile,
header: QcowHeader, header: QcowHeader,
@@ -445,7 +386,7 @@ pub struct QcowFile {
// List of unreferenced clusters available to be used. unref clusters become available once the // List of unreferenced clusters available to be used. unref clusters become available once the
// removal of references to them have been synced to disk. // removal of references to them have been synced to disk.
avail_clusters: Vec<u64>, avail_clusters: Vec<u64>,
backing_file: Option<Box<dyn BlockBackend>>, //TODO(dgreid) Add support for backing files. - backing_file: Option<Box<QcowFile<T>>>,
} }
impl QcowFile { impl QcowFile {
@@ -474,20 +415,10 @@ impl QcowFile {
return Err(Error::FileTooBig(header.size)); return Err(Error::FileTooBig(header.size));
} }
let direct_io = file.is_direct(); // No current support for backing files.
if header.backing_file_offset != 0 {
let backing_file = if let Some(backing_file_path) = header.backing_file_path.as_ref() { return Err(Error::BackingFilesNotSupported);
let path = backing_file_path.clone(); }
let backing_raw_file = OpenOptions::new()
.read(true)
.open(path)
.map_err(Error::BackingFileIo)?;
let backing_file = crate::create_disk_file(backing_raw_file, direct_io)
.map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
Some(backing_file)
} else {
None
};
// Only support two byte refcounts. // Only support two byte refcounts.
let refcount_bits: u64 = 0x01u64 let refcount_bits: u64 = 0x01u64
@@ -502,6 +433,7 @@ impl QcowFile {
if header.refcount_table_clusters == 0 { if header.refcount_table_clusters == 0 {
return Err(Error::NoRefcountClusters); return Err(Error::NoRefcountClusters);
} }
offset_is_cluster_boundary(header.backing_file_offset, header.cluster_bits)?;
offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)?; offset_is_cluster_boundary(header.l1_table_offset, header.cluster_bits)?;
offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)?; offset_is_cluster_boundary(header.snapshots_offset, header.cluster_bits)?;
// refcount table must be a cluster boundary, and within the file's virtual or actual size. // refcount table must be a cluster boundary, and within the file's virtual or actual size.
@@ -534,7 +466,7 @@ impl QcowFile {
let mut raw_file = let mut raw_file =
QcowRawFile::from(file, cluster_size).ok_or(Error::InvalidClusterSize)?; QcowRawFile::from(file, cluster_size).ok_or(Error::InvalidClusterSize)?;
if refcount_rebuild_required { if refcount_rebuild_required {
QcowFile::rebuild_refcounts(&mut raw_file, header.clone())?; QcowFile::rebuild_refcounts(&mut raw_file, header)?;
} }
let entries_per_cluster = cluster_size / size_of::<u64>() as u64; let entries_per_cluster = cluster_size / size_of::<u64>() as u64;
@@ -603,7 +535,6 @@ impl QcowFile {
current_offset: 0, current_offset: 0,
unref_clusters: Vec::new(), unref_clusters: Vec::new(),
avail_clusters: Vec::new(), avail_clusters: Vec::new(),
backing_file,
}; };
// Check that the L1 and refcount tables fit in a 64bit address space. // Check that the L1 and refcount tables fit in a 64bit address space.
@@ -622,34 +553,8 @@ impl QcowFile {
} }
/// Creates a new QcowFile at the given path. /// Creates a new QcowFile at the given path.
pub fn new(file: RawFile, version: u32, virtual_size: u64) -> Result<QcowFile> { pub fn new(mut file: RawFile, version: u32, virtual_size: u64) -> Result<QcowFile> {
let header = QcowHeader::create_for_size_and_path(version, virtual_size, None)?; let header = QcowHeader::create_for_size(version, virtual_size);
QcowFile::new_from_header(file, header)
}
/// Creates a new QcowFile at the given path.
pub fn new_from_backing(
file: RawFile,
version: u32,
backing_file_name: &str,
) -> Result<QcowFile> {
let direct_io = file.is_direct();
let backing_raw_file = OpenOptions::new()
.read(true)
.open(backing_file_name)
.map_err(Error::BackingFileIo)?;
let backing_file = crate::create_disk_file(backing_raw_file, direct_io)
.map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
let size = backing_file
.size()
.map_err(|e| Error::BackingFileOpen(Box::new(e)))?;
let header = QcowHeader::create_for_size_and_path(version, size, Some(backing_file_name))?;
let mut result = QcowFile::new_from_header(file, header)?;
result.backing_file = Some(backing_file);
Ok(result)
}
fn new_from_header(mut file: RawFile, header: QcowHeader) -> Result<QcowFile> {
file.rewind().map_err(Error::SeekingFile)?; file.rewind().map_err(Error::SeekingFile)?;
header.write_to(&mut file)?; header.write_to(&mut file)?;
@@ -673,10 +578,6 @@ impl QcowFile {
Ok(qcow) Ok(qcow)
} }
pub fn set_backing_file(&mut self, backing: Option<Box<dyn BlockBackend>>) {
self.backing_file = backing;
}
/// Returns the `QcowHeader` for this file. /// Returns the `QcowHeader` for this file.
pub fn header(&self) -> &QcowHeader { pub fn header(&self) -> &QcowHeader {
&self.header &self.header
@@ -989,9 +890,9 @@ impl QcowFile {
// Find all references clusters and rebuild refcounts. // Find all references clusters and rebuild refcounts.
set_header_refcount(&mut refcounts, cluster_size)?; set_header_refcount(&mut refcounts, cluster_size)?;
set_l1_refcounts(&mut refcounts, header.clone(), cluster_size)?; set_l1_refcounts(&mut refcounts, header, cluster_size)?;
set_data_refcounts(&mut refcounts, header.clone(), cluster_size, raw_file)?; set_data_refcounts(&mut refcounts, header, cluster_size, raw_file)?;
set_refcount_table_refcounts(&mut refcounts, header.clone(), cluster_size)?; set_refcount_table_refcounts(&mut refcounts, header, cluster_size)?;
// Allocate clusters to store the new reference count blocks. // Allocate clusters to store the new reference count blocks.
let ref_table = alloc_refblocks(&mut refcounts, cluster_size, refblock_clusters)?; let ref_table = alloc_refblocks(&mut refcounts, cluster_size, refblock_clusters)?;
@@ -1106,7 +1007,7 @@ impl QcowFile {
let l2_table = if l2_addr_disk == 0 { let l2_table = if l2_addr_disk == 0 {
// Allocate a new cluster to store the L2 table and update the L1 table to point // Allocate a new cluster to store the L2 table and update the L1 table to point
// to the new table. // to the new table.
let new_addr: u64 = self.get_new_cluster(None)?; let new_addr: u64 = self.get_new_cluster()?;
// The cluster refcount starts at one meaning it is used but doesn't need COW. // The cluster refcount starts at one meaning it is used but doesn't need COW.
set_refcounts.push((new_addr, 1)); set_refcounts.push((new_addr, 1));
self.l1_table[l1_index] = new_addr; self.l1_table[l1_index] = new_addr;
@@ -1127,18 +1028,8 @@ impl QcowFile {
let cluster_addr = match self.l2_cache.get(l1_index).unwrap()[l2_index] { let cluster_addr = match self.l2_cache.get(l1_index).unwrap()[l2_index] {
0 => { 0 => {
let initial_data = if let Some(backing) = self.backing_file.as_mut() {
let cluster_size = self.raw_file.cluster_size();
let cluster_begin = address - (address % cluster_size);
let mut cluster_data = vec![0u8; cluster_size as usize];
backing.seek(SeekFrom::Start(cluster_begin))?;
backing.read_exact(&mut cluster_data)?;
Some(cluster_data)
} else {
None
};
// Need to allocate a data cluster // Need to allocate a data cluster
let cluster_addr = self.append_data_cluster(initial_data)?; let cluster_addr = self.append_data_cluster()?;
self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?; self.update_cluster_addr(l1_index, l2_index, cluster_addr, &mut set_refcounts)?;
cluster_addr cluster_addr
} }
@@ -1175,7 +1066,7 @@ impl QcowFile {
// Allocate a new cluster to store the L2 table and update the L1 table to point // Allocate a new cluster to store the L2 table and update the L1 table to point
// to the new table. The cluster will be written when the cache is flushed, no // to the new table. The cluster will be written when the cache is flushed, no
// need to copy the data now. // need to copy the data now.
let new_addr: u64 = self.get_new_cluster(None)?; let new_addr: u64 = self.get_new_cluster()?;
// The cluster refcount starts at one indicating it is used but doesn't need // The cluster refcount starts at one indicating it is used but doesn't need
// COW. // COW.
set_refcounts.push((new_addr, 1)); set_refcounts.push((new_addr, 1));
@@ -1187,22 +1078,15 @@ impl QcowFile {
} }
// Allocate a new cluster and return its offset within the raw file. // Allocate a new cluster and return its offset within the raw file.
fn get_new_cluster(&mut self, initial_data: Option<Vec<u8>>) -> std::io::Result<u64> { fn get_new_cluster(&mut self) -> std::io::Result<u64> {
// First use a pre allocated cluster if one is available. // First use a pre allocated cluster if one is available.
if let Some(free_cluster) = self.avail_clusters.pop() { if let Some(free_cluster) = self.avail_clusters.pop() {
if let Some(initial_data) = initial_data { self.raw_file.zero_cluster(free_cluster)?;
self.raw_file.write_cluster(free_cluster, initial_data)?;
} else {
self.raw_file.zero_cluster(free_cluster)?;
}
return Ok(free_cluster); return Ok(free_cluster);
} }
let max_valid_cluster_offset = self.refcounts.max_valid_cluster_offset(); let max_valid_cluster_offset = self.refcounts.max_valid_cluster_offset();
if let Some(new_cluster) = self.raw_file.add_cluster_end(max_valid_cluster_offset)? { if let Some(new_cluster) = self.raw_file.add_cluster_end(max_valid_cluster_offset)? {
if let Some(initial_data) = initial_data {
self.raw_file.write_cluster(new_cluster, initial_data)?;
}
Ok(new_cluster) Ok(new_cluster)
} else { } else {
error!("No free clusters in get_new_cluster()"); error!("No free clusters in get_new_cluster()");
@@ -1212,8 +1096,8 @@ impl QcowFile {
// Allocate and initialize a new data cluster. Returns the offset of the // Allocate and initialize a new data cluster. Returns the offset of the
// cluster in to the file on success. // cluster in to the file on success.
fn append_data_cluster(&mut self, initial_data: Option<Vec<u8>>) -> std::io::Result<u64> { fn append_data_cluster(&mut self) -> std::io::Result<u64> {
let new_addr: u64 = self.get_new_cluster(initial_data)?; let new_addr: u64 = self.get_new_cluster()?;
// The cluster refcount starts at one indicating it is used but doesn't need COW. // The cluster refcount starts at one indicating it is used but doesn't need COW.
let mut newly_unref = self.set_cluster_refcount(new_addr, 1)?; let mut newly_unref = self.set_cluster_refcount(new_addr, 1)?;
self.unref_clusters.append(&mut newly_unref); self.unref_clusters.append(&mut newly_unref);
@@ -1447,7 +1331,7 @@ impl QcowFile {
} }
Err(refcount::Error::NeedNewCluster) => { Err(refcount::Error::NeedNewCluster) => {
// Allocate the cluster and call set_cluster_refcount again. // Allocate the cluster and call set_cluster_refcount again.
let addr = self.get_new_cluster(None)?; let addr = self.get_new_cluster()?;
added_clusters.push(addr); added_clusters.push(addr);
new_cluster = Some(( new_cluster = Some((
addr, addr,
@@ -1530,9 +1414,6 @@ impl Read for QcowFile {
self.raw_file self.raw_file
.file_mut() .file_mut()
.read_exact(&mut buf[nread..(nread + count)])?; .read_exact(&mut buf[nread..(nread + count)])?;
} else if let Some(backing) = self.backing_file.as_mut() {
backing.seek(SeekFrom::Start(curr_addr))?;
backing.read_exact(&mut buf[nread..(nread + count)])?;
} else { } else {
// Previously unwritten region, return zeros // Previously unwritten region, return zeros
for b in &mut buf[nread..(nread + count)] { for b in &mut buf[nread..(nread + count)] {
@@ -1675,12 +1556,6 @@ impl SeekHole for QcowFile {
} }
} }
impl BlockBackend for QcowFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.virtual_size())
}
}
// Returns an Error if the given offset doesn't align to a cluster boundary. // Returns an Error if the given offset doesn't align to a cluster boundary.
fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> { fn offset_is_cluster_boundary(offset: u64, cluster_bits: u32) -> Result<()> {
if offset & ((0x01 << cluster_bits) - 1) != 0 { if offset & ((0x01 << cluster_bits) - 1) != 0 {
@@ -1891,19 +1766,16 @@ mod tests {
] ]
} }
fn basic_file(header: &[u8]) -> RawFile {
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
disk_file.write_all(header).unwrap();
disk_file.set_len(0x1_0000_0000).unwrap();
disk_file.rewind().unwrap();
disk_file
}
fn with_basic_file<F>(header: &[u8], mut testfn: F) fn with_basic_file<F>(header: &[u8], mut testfn: F)
where where
F: FnMut(RawFile), F: FnMut(RawFile),
{ {
testfn(basic_file(header)); // File closed when the function exits. let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
disk_file.write_all(header).unwrap();
disk_file.set_len(0x1_0000_0000).unwrap();
disk_file.rewind().unwrap();
testfn(disk_file); // File closed when the function exits.
} }
fn with_default_file<F>(file_size: u64, direct: bool, mut testfn: F) fn with_default_file<F>(file_size: u64, direct: bool, mut testfn: F)
@@ -1916,44 +1788,11 @@ mod tests {
testfn(qcow_file); // File closed when the function exits. testfn(qcow_file); // File closed when the function exits.
} }
#[test]
fn write_read_start_backing_v2() {
let disk_file = basic_file(&valid_header_v2());
let mut backing = QcowFile::from(disk_file).unwrap();
backing
.write_all(b"test first bytes")
.expect("Failed to write test string.");
let mut buf = [0u8; 4];
let wrapping_disk_file = basic_file(&valid_header_v2());
let mut wrapping = QcowFile::from(wrapping_disk_file).unwrap();
wrapping.set_backing_file(Some(Box::new(backing)));
wrapping.seek(SeekFrom::Start(0)).expect("Failed to seek.");
wrapping.read_exact(&mut buf).expect("Failed to read.");
assert_eq!(&buf, b"test");
}
#[test]
fn write_read_start_backing_v3() {
let disk_file = basic_file(&valid_header_v3());
let mut backing = QcowFile::from(disk_file).unwrap();
backing
.write_all(b"test first bytes")
.expect("Failed to write test string.");
let mut buf = [0u8; 4];
let wrapping_disk_file = basic_file(&valid_header_v3());
let mut wrapping = QcowFile::from(wrapping_disk_file).unwrap();
wrapping.set_backing_file(Some(Box::new(backing)));
wrapping.seek(SeekFrom::Start(0)).expect("Failed to seek.");
wrapping.read_exact(&mut buf).expect("Failed to read.");
assert_eq!(&buf, b"test");
}
#[test] #[test]
fn default_header_v2() { fn default_header_v2() {
let header = QcowHeader::create_for_size_and_path(2, 0x10_0000, None); let header = QcowHeader::create_for_size(2, 0x10_0000);
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false); let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
header header
.expect("Failed to create header.")
.write_to(&mut disk_file) .write_to(&mut disk_file)
.expect("Failed to write header to temporary file."); .expect("Failed to write header to temporary file.");
disk_file.rewind().unwrap(); disk_file.rewind().unwrap();
@@ -1962,10 +1801,9 @@ mod tests {
#[test] #[test]
fn default_header_v3() { fn default_header_v3() {
let header = QcowHeader::create_for_size_and_path(3, 0x10_0000, None); let header = QcowHeader::create_for_size(3, 0x10_0000);
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false); let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
header header
.expect("Failed to create header.")
.write_to(&mut disk_file) .write_to(&mut disk_file)
.expect("Failed to write header to temporary file."); .expect("Failed to write header to temporary file.");
disk_file.rewind().unwrap(); disk_file.rewind().unwrap();
@@ -1988,40 +1826,6 @@ mod tests {
}); });
} }
#[test]
fn header_v2_with_backing() {
let header = QcowHeader::create_for_size_and_path(2, 0x10_0000, Some("/my/path/to/a/file"))
.expect("Failed to create header.");
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
header
.write_to(&mut disk_file)
.expect("Failed to write header to shm.");
disk_file.rewind().unwrap();
let read_header = QcowHeader::new(&mut disk_file).expect("Failed to create header.");
assert_eq!(
header.backing_file_path,
Some(String::from("/my/path/to/a/file"))
);
assert_eq!(read_header.backing_file_path, header.backing_file_path);
}
#[test]
fn header_v3_with_backing() {
let header = QcowHeader::create_for_size_and_path(3, 0x10_0000, Some("/my/path/to/a/file"))
.expect("Failed to create header.");
let mut disk_file: RawFile = RawFile::new(TempFile::new().unwrap().into_file(), false);
header
.write_to(&mut disk_file)
.expect("Failed to write header to shm.");
disk_file.rewind().unwrap();
let read_header = QcowHeader::new(&mut disk_file).expect("Failed to create header.");
assert_eq!(
header.backing_file_path,
Some(String::from("/my/path/to/a/file"))
);
assert_eq!(read_header.backing_file_path, header.backing_file_path);
}
#[test] #[test]
fn invalid_magic() { fn invalid_magic() {
let invalid_header = vec![0x51u8, 0x46, 0x4a, 0xfb]; let invalid_header = vec![0x51u8, 0x46, 0x4a, 0xfb];
@@ -2136,26 +1940,6 @@ mod tests {
}); });
} }
#[test]
fn write_read_start_backing_overlap() {
let disk_file = basic_file(&valid_header_v3());
let mut backing = QcowFile::from(disk_file).unwrap();
backing
.write_all(b"test first bytes")
.expect("Failed to write test string.");
let wrapping_disk_file = basic_file(&valid_header_v3());
let mut wrapping = QcowFile::from(wrapping_disk_file).unwrap();
wrapping.set_backing_file(Some(Box::new(backing)));
wrapping.seek(SeekFrom::Start(0)).expect("Failed to seek.");
wrapping
.write_all(b"TEST")
.expect("Failed to write second test string.");
let mut buf = [0u8; 10];
wrapping.seek(SeekFrom::Start(0)).expect("Failed to seek.");
wrapping.read_exact(&mut buf).expect("Failed to read.");
assert_eq!(&buf, b"TEST first");
}
#[test] #[test]
fn offset_write_read() { fn offset_write_read() {
with_basic_file(&valid_header_v3(), |disk_file: RawFile| { with_basic_file(&valid_header_v3(), |disk_file: RawFile| {

View File

@@ -4,7 +4,7 @@
use super::RawFile; use super::RawFile;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use std::io::{self, BufWriter, Seek, SeekFrom, Write}; use std::io::{self, BufWriter, Seek, SeekFrom};
use std::mem::size_of; use std::mem::size_of;
use vmm_sys_util::write_zeroes::WriteZeroes; use vmm_sys_util::write_zeroes::WriteZeroes;
@@ -92,7 +92,6 @@ impl QcowRawFile {
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(std::mem::size_of_val(table), &mut self.file);
for count in table { for count in table {
buffer.write_u16::<BigEndian>(*count)?; buffer.write_u16::<BigEndian>(*count)?;
} }
@@ -137,13 +136,6 @@ impl QcowRawFile {
self.file.write_zeroes(cluster_size)?; self.file.write_zeroes(cluster_size)?;
Ok(()) Ok(())
} }
/// Writes
pub fn write_cluster(&mut self, address: u64, data: Vec<u8>) -> io::Result<()> {
let cluster_size = self.cluster_size as usize;
self.file.seek(SeekFrom::Start(address))?;
self.file.write_all(&data[0..cluster_size])
}
} }
impl Clone for QcowRawFile { impl Clone for QcowRawFile {

View File

@@ -8,7 +8,6 @@
// //
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use crate::BlockBackend;
use libc::c_void; use libc::c_void;
use std::alloc::{alloc_zeroed, dealloc, Layout}; use std::alloc::{alloc_zeroed, dealloc, Layout};
use std::convert::TryInto; use std::convert::TryInto;
@@ -23,7 +22,6 @@ pub struct RawFile {
file: File, file: File,
alignment: usize, alignment: usize,
position: u64, position: u64,
direct_io: bool,
} }
const BLK_ALIGNMENTS: [usize; 2] = [512, 4096]; const BLK_ALIGNMENTS: [usize; 2] = [512, 4096];
@@ -66,7 +64,6 @@ impl RawFile {
file, file,
alignment, alignment,
position: 0, position: 0,
direct_io,
} }
} }
@@ -105,7 +102,6 @@ impl RawFile {
file: self.file.try_clone().expect("RawFile cloning failed"), file: self.file.try_clone().expect("RawFile cloning failed"),
alignment: self.alignment, alignment: self.alignment,
position: self.position, position: self.position,
direct_io: self.direct_io,
}) })
} }
@@ -116,10 +112,6 @@ impl RawFile {
pub fn sync_data(&self) -> std::io::Result<()> { pub fn sync_data(&self) -> std::io::Result<()> {
self.file.sync_data() self.file.sync_data()
} }
pub fn is_direct(&self) -> bool {
self.direct_io
}
} }
impl Read for RawFile { impl Read for RawFile {
@@ -351,19 +343,12 @@ impl SeekHole for RawFile {
} }
} }
impl BlockBackend for RawFile {
fn size(&self) -> std::result::Result<u64, crate::Error> {
Ok(self.metadata().map_err(crate::Error::RawFileError)?.len())
}
}
impl Clone for RawFile { impl Clone for RawFile {
fn clone(&self) -> Self { fn clone(&self) -> Self {
RawFile { RawFile {
file: self.file.try_clone().expect("RawFile cloning failed"), file: self.file.try_clone().expect("RawFile cloning failed"),
alignment: self.alignment, alignment: self.alignment,
position: self.position, position: self.position,
direct_io: self.direct_io,
} }
} }
} }

View File

@@ -7,10 +7,8 @@ use std::io;
use libc::EINVAL; use libc::EINVAL;
use crate::qcow::{ use crate::qcow_raw_file::QcowRawFile;
qcow_raw_file::QcowRawFile, use crate::vec_cache::{CacheMap, Cacheable, VecCache};
vec_cache::{CacheMap, Cacheable, VecCache},
};
#[derive(Debug)] #[derive(Debug)]
pub enum Error { pub enum Error {

View File

@@ -1,20 +1,4 @@
- [v34.0](#v340) - [v31.2](#v312)
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v33.0](#v330)
- [D-Bus based API](#d-bus-based-api)
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v32.0](#v320)
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
- [API Changes](#api-changes)
- [Notable Bug Fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [v31.1](#v311) - [v31.1](#v311)
- [v31.0](#v310) - [v31.0](#v310)
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables) - [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
@@ -22,15 +6,15 @@
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler) - [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile) - [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
- [Documentation Improvements](#documentation-improvements) - [Documentation Improvements](#documentation-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-3) - [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors-3) - [Contributors](#contributors)
- [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-1)
- [Notable Bug Fixes](#notable-bug-fixes-4) - [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-4) - [Contributors](#contributors-1)
- [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)
@@ -40,10 +24,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-5) - [Notable Bug Fixes](#notable-bug-fixes-2)
- [Removals](#removals) - [Removals](#removals)
- [Deprecations](#deprecations) - [Deprecations](#deprecations)
- [Contributors](#contributors-5) - [Contributors](#contributors-2)
- [v28.1](#v281) - [v28.1](#v281)
- [v28.0](#v280) - [v28.0](#v280)
- [Community Engagement (Reminder)](#community-engagement-reminder) - [Community Engagement (Reminder)](#community-engagement-reminder)
@@ -51,9 +35,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-6) - [Notable Bug Fixes](#notable-bug-fixes-3)
- [Removals](#removals-1) - [Removals](#removals-1)
- [Contributors](#contributors-6) - [Contributors](#contributors-3)
- [v27.0](#v270) - [v27.0](#v270)
- [Community Engagement](#community-engagement) - [Community Engagement](#community-engagement)
- [Prebuilt Packages](#prebuilt-packages) - [Prebuilt Packages](#prebuilt-packages)
@@ -62,41 +46,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-7) - [Notable Bug Fixes](#notable-bug-fixes-4)
- [Deprecations](#deprecations-1) - [Deprecations](#deprecations-1)
- [Contributors](#contributors-7) - [Contributors](#contributors-4)
- [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-8) - [Notable Bug Fixes](#notable-bug-fixes-5)
- [Deprecations](#deprecations-2) - [Deprecations](#deprecations-2)
- [Removals](#removals-2) - [Removals](#removals-2)
- [Contributors](#contributors-8) - [Contributors](#contributors-5)
- [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-9) - [Notable Bug Fixes](#notable-bug-fixes-6)
- [Removals](#removals-3) - [Removals](#removals-3)
- [Contributors](#contributors-9) - [Contributors](#contributors-6)
- [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-10) - [Notable Bug Fixes](#notable-bug-fixes-7)
- [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-10) - [Contributors](#contributors-7)
- [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-11) - [Notable Bug Fixes](#notable-bug-fixes-8)
- [Deprecations](#deprecations-4) - [Deprecations](#deprecations-4)
- [Contributors](#contributors-11) - [Contributors](#contributors-8)
- [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)
@@ -107,13 +91,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-12) - [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-12) - [Contributors](#contributors-9)
- [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-13) - [Notable Bug fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-13) - [Contributors](#contributors-10)
- [v20.2](#v202) - [v20.2](#v202)
- [v20.1](#v201) - [v20.1](#v201)
- [v20.0](#v200) - [v20.0](#v200)
@@ -122,8 +106,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-14) - [Notable bug fixes](#notable-bug-fixes-11)
- [Contributors](#contributors-14) - [Contributors](#contributors-11)
- [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)
@@ -131,8 +115,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-15) - [Notable bug fixes](#notable-bug-fixes-12)
- [Contributors](#contributors-15) - [Contributors](#contributors-12)
- [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)
@@ -142,23 +126,23 @@
- [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-16) - [Notable bug fixes](#notable-bug-fixes-13)
- [Contributors](#contributors-16) - [Contributors](#contributors-13)
- [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-17) - [Notable bug fixes](#notable-bug-fixes-14)
- [Contributors](#contributors-17) - [Contributors](#contributors-14)
- [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-18) - [Notable bug fixes](#notable-bug-fixes-15)
- [Removed functionality](#removed-functionality) - [Removed functionality](#removed-functionality)
- [Contributors](#contributors-18) - [Contributors](#contributors-15)
- [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)
@@ -166,7 +150,7 @@
- [`--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-19) - [Contributors](#contributors-16)
- [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)
@@ -176,7 +160,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-20) - [Contributors](#contributors-17)
- [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)
@@ -184,13 +168,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-21) - [Contributors](#contributors-18)
- [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-22) - [Contributors](#contributors-19)
- [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)
@@ -202,15 +186,15 @@
- [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-19) - [Notable Bug Fixes](#notable-bug-fixes-16)
- [Contributors](#contributors-23) - [Contributors](#contributors-20)
- [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-20) - [Notable Bug Fixes](#notable-bug-fixes-17)
- [Contributors](#contributors-24) - [Contributors](#contributors-21)
- [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)
@@ -223,17 +207,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-21) - [Notable Bug Fixes](#notable-bug-fixes-18)
- [Contributors](#contributors-25) - [Contributors](#contributors-22)
- [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-22) - [Notable Bug Fixes](#notable-bug-fixes-19)
- [Command Line and API Changes](#command-line-and-api-changes) - [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-26) - [Contributors](#contributors-23)
- [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)
@@ -243,14 +227,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-27) - [Contributors](#contributors-24)
- [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-28) - [Contributors](#contributors-25)
- [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)
@@ -258,7 +242,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-29) - [Contributors](#contributors-26)
- [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)
@@ -267,7 +251,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-30) - [Contributors](#contributors-27)
- [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)
@@ -294,153 +278,23 @@
- [Unit testing](#unit-testing) - [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization) - [Integration tests parallelization](#integration-tests-parallelization)
# v34.0 # v31.2
This release has been tracked in our [roadmap This is a bug fix release. The following issues have been addressed:
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
v34.0. The following user visible changes have been made:
### Paravirtualised Panic Device Support
A new device has been added that can communicate when the guest kernel has
panicked and share those details with the VMM. This is controlled with a new
`--pvpanic` command line option and JSON API change equivalent. (#5526)
### Improvements to VM Core Dump
Requesting to dump the guest memory as core dump will now transparently pause
the VM if required; returning to the original state after. (#5604)
### QCOW2 Support for Backing Files
The support for QCOW2 files has been enhanced to include support for using
backing files. (#5573)
### Minimum Host Kernel Bump
The minimum supported host kernel is now 5.13 in order to incorporate a bug fix
for `KVM_FEATURE_ASYNC_PF_INT` functionality. (#5626)
### Notable Bug Fixes
* The x86 emulator is only compiled in if MSHV is compiled in (the kernel
carries out this job with KVM) (#5561).
* A regression has been fixed in VFIO support for devices that use MSI rather
than MSI-X (#5658).
* When triggering a VM shutdown or reset via I/O the vCPU thread will be
blocked until that asynchronous event has been received (#5645).
* Pausing a VM is now a synchronous action with the request only completing
when all vCPUs are paused (#5611).
* Event monitor support now correctly supports concurrent access (#5633).
* Bug fixes for the QCOW2 file support (#5573).
### 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>
* Changyuan Lyu <changyuanl@google.com>
* Christian Blichmann <cblichmann@google.com>
* Manish Goregaokar <manishsmail@gmail.com>
* Omer Faruk Bayram <omer.faruk@sartura.hr>
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
* Praveen K Paladugu <prapal@linux.microsoft.com>
* Rob Bradford <rbradford@rivosinc.com>
* Ruslan Mstoi <ruslan.mstoi@intel.com>
* Yi Wang <foxywang@tencent.com>
* Yong He <alexyonghe@tencent.com>
* Yu Li <liyu.yukiteru@bytedance.com>
* dom.song <dom.song@amperecomputing.com>
# v33.0
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
* The number of vCPUs is capped at the hypervisor maximum (#5357)
* Fixes for TTY reset (#5414)
* CPU topology fixes on MSHV (#5325)
* Seccomp fixes for older distributions (#5397)
* Report errors explicitly to users when VM failed to boot (#5453) * Report errors explicitly to users when VM failed to boot (#5453)
* Fix VFIO on platforms with non-4k page size (#5450, #5469) * Fix VFIO on platforms with non-4k page size (#5450, #5469)
* Fix TDX initialization (#5454) * Fix TDX initialization (#5454)
* Ensure all guest memory regions are page-size aligned (#5496) * Ensure all guest memory regions are page-size aligned (#5496)
* Fix seccomp filter lists related to virtio-console, serial and pty * Fix seccomp filter lists related to virtio-console, serial and pty
(#5506, #5524) (#5506, #5524)
* Populate APIC ID properly (#5512) * Populate APIC ID properly (#5512)
* Ignore and warn TAP FDs in more situations (#5522) * 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 # 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:

View File

@@ -15,67 +15,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 +74,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 +84,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 +96,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 +108,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 +123,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) TARGET_ARCHITECTURE=skylake \ && 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 +131,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 +151,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

@@ -1402,8 +1402,7 @@ CONFIG_NVME_MULTIPATH=y
# CONFIG_MISC_RTSX_PCI is not set # CONFIG_MISC_RTSX_PCI is not set
# CONFIG_HABANA_AI is not set # CONFIG_HABANA_AI is not set
# CONFIG_UACCE is not set # CONFIG_UACCE is not set
CONFIG_PVPANIC=y # CONFIG_PVPANIC is not set
CONFIG_PVPANIC_PCI=y
# CONFIG_GP_PCI1XXXX is not set # CONFIG_GP_PCI1XXXX is not set
# end of Misc devices # end of Misc devices
@@ -3051,16 +3050,23 @@ CONFIG_SYMBOLIC_ERRNAME=y
# end of printk and dmesg options # end of printk and dmesg options
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_MISC is not set CONFIG_DEBUG_MISC=y
# #
# Compile-time checks and compiler options # Compile-time checks and compiler options
# #
CONFIG_DEBUG_INFO=y
CONFIG_AS_HAS_NON_CONST_LEB128=y CONFIG_AS_HAS_NON_CONST_LEB128=y
CONFIG_DEBUG_INFO_NONE=y # CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set 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_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set
CONFIG_FRAME_WARN=2048 CONFIG_FRAME_WARN=2048
CONFIG_STRIP_ASM_SYMS=y CONFIG_STRIP_ASM_SYMS=y
# CONFIG_READABLE_ASM is not set # CONFIG_READABLE_ASM is not set

View File

@@ -1378,8 +1378,7 @@ CONFIG_NVME_MULTIPATH=y
# CONFIG_MISC_RTSX_PCI is not set # CONFIG_MISC_RTSX_PCI is not set
# CONFIG_HABANA_AI is not set # CONFIG_HABANA_AI is not set
# CONFIG_UACCE is not set # CONFIG_UACCE is not set
CONFIG_PVPANIC=y # CONFIG_PVPANIC is not set
CONFIG_PVPANIC_PCI=y
# CONFIG_GP_PCI1XXXX is not set # CONFIG_GP_PCI1XXXX is not set
# end of Misc devices # end of Misc devices
@@ -2925,16 +2924,23 @@ CONFIG_SYMBOLIC_ERRNAME=y
# end of printk and dmesg options # end of printk and dmesg options
CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_KERNEL=y
# CONFIG_DEBUG_MISC is not set CONFIG_DEBUG_MISC=y
# #
# Compile-time checks and compiler options # Compile-time checks and compiler options
# #
CONFIG_DEBUG_INFO=y
CONFIG_AS_HAS_NON_CONST_LEB128=y CONFIG_AS_HAS_NON_CONST_LEB128=y
CONFIG_DEBUG_INFO_NONE=y # CONFIG_DEBUG_INFO_NONE is not set
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set 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_COMPRESSED_NONE=y
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
# CONFIG_DEBUG_INFO_SPLIT is not set
# CONFIG_DEBUG_INFO_BTF is not set
# CONFIG_GDB_SCRIPTS is not set
CONFIG_FRAME_WARN=2048 CONFIG_FRAME_WARN=2048
CONFIG_STRIP_ASM_SYMS=y CONFIG_STRIP_ASM_SYMS=y
# CONFIG_READABLE_ASM is not set # CONFIG_READABLE_ASM 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

@@ -7,8 +7,8 @@
CLI_NAME="Cloud Hypervisor" CLI_NAME="Cloud Hypervisor"
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor" CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
CTR_IMAGE_VERSION="20230804-0" CTR_IMAGE_VERSION="20230316-0"
: "${CTR_IMAGE:=${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}}" CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker" DOCKER_RUNTIME="docker"
@@ -426,7 +426,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 +539,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

@@ -95,14 +95,6 @@ update_workloads() {
popd popd
fi fi
FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME="focal-server-cloudimg-arm64-custom-20210929-0-backing.qcow2"
FOCAL_OS_QCOW2_BACKING_FILE_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME"
if [ ! -f "$FOCAL_OS_QCOW2_BACKING_FILE_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img create -f qcow2 -b $FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE -F qcow2 $FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME
popd
fi
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.raw" JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.raw"
JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_RAW_IMAGE_NAME" JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_RAW_IMAGE_NAME"
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME" JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
@@ -233,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
@@ -289,12 +281,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

@@ -15,7 +15,7 @@ process_common_args "$@"
test_features="" test_features=""
if [ "$hypervisor" = "mshv" ] ; then if [ "$hypervisor" = "mshv" ] ; then
test_features="--features mshv" test_features="--no-default-features --features mshv"
fi fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
@@ -68,7 +68,7 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
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 --features 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}'` HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`

View File

@@ -15,7 +15,7 @@ process_common_args "$@"
test_features="" test_features=""
if [ "$hypervisor" = "mshv" ] ; then if [ "$hypervisor" = "mshv" ] ; then
test_features="--features mshv" test_features="--no-default-features --features mshv"
fi fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
@@ -55,7 +55,7 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
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 --features mshv --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
time cargo test $test_features "rate_limiter::$test_filter" -- --test-threads=1 ${test_binary_args[*]} time cargo test $test_features "rate_limiter::$test_filter" -- --test-threads=1 ${test_binary_args[*]}

View File

@@ -42,11 +42,11 @@ 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 --features mshv --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1

View File

@@ -7,42 +7,9 @@ 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 build_custom_linux
@@ -64,7 +31,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
@@ -76,7 +43,7 @@ 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 --features mshv --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# We always copy a fresh version of our binary for our L2 guest. # We always copy a fresh version of our binary for our L2 guest.
cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR

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

@@ -9,7 +9,7 @@ process_common_args "$@"
test_features="" test_features=""
if [ "$hypervisor" = "mshv" ] ; then if [ "$hypervisor" = "mshv" ] ; then
test_features="--features mshv" test_features="--no-default-features --features mshv"
fi fi
WIN_IMAGE_FILE="/root/workloads/windows-server-2022-amd64-2.raw" WIN_IMAGE_FILE="/root/workloads/windows-server-2022-amd64-2.raw"
@@ -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
@@ -44,7 +44,7 @@ dmsetup mknodes
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base" dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
dmsetup mknodes dmsetup mknodes
cargo build --features mshv --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1

View File

@@ -15,7 +15,7 @@ process_common_args "$@"
test_features="" test_features=""
if [ "$hypervisor" = "mshv" ] ; then if [ "$hypervisor" = "mshv" ] ; then
test_features="--features mshv" test_features="--no-default-features --features mshv"
fi fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
@@ -53,14 +53,6 @@ if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
popd popd
fi fi
FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0-backing.qcow2"
FOCAL_OS_QCOW_BACKING_FILE_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME"
if [ ! -f "$FOCAL_OS_QCOW_BACKING_FILE_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img create -f qcow2 -b $FOCAL_OS_IMAGE -F qcow2 $FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME
popd
fi
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2" JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME" JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
@@ -164,7 +156,7 @@ cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}" BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
cargo build --features mshv --all --release --target $BUILD_TARGET cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
# We always copy a fresh version of our binary for our L2 guest. # We always copy a fresh version of our binary for our L2 guest.
cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
@@ -185,9 +177,6 @@ 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
ulimit -l unlimited ulimit -l unlimited
# Set number of open descriptors high enough for VFIO tests to run
ulimit -n 4096
export RUST_BACKTRACE=1 export RUST_BACKTRACE=1
time cargo test $test_features "common_parallel::$test_filter" -- ${test_binary_args[*]} time cargo test $test_features "common_parallel::$test_filter" -- ${test_binary_args[*]}
RES=$? RES=$?
@@ -200,13 +189,4 @@ if [ $RES -eq 0 ]; then
RES=$? RES=$?
fi fi
# Run tests on dbus_api
if [ $RES -eq 0 ]; then
cargo build --features "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

@@ -92,7 +92,7 @@ if [[ "${BUILD_TARGET}" == "${TEST_ARCH}-unknown-linux-musl" ]]; then
CFLAGS="-I /usr/include/${TEST_ARCH}-linux-musl/ -idirafter /usr/include/" CFLAGS="-I /usr/include/${TEST_ARCH}-linux-musl/ -idirafter /usr/include/"
fi fi
cargo build --features 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}'` HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
@@ -107,12 +107,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

@@ -9,6 +9,7 @@ BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
cargo_args=("") cargo_args=("")
if [[ $hypervisor = "mshv" ]]; then if [[ $hypervisor = "mshv" ]]; then
cargo_args+=("--no-default-features")
cargo_args+=("--features $hypervisor") cargo_args+=("--features $hypervisor")
elif [[ $(uname -m) = "x86_64" ]]; then elif [[ $(uname -m) = "x86_64" ]]; then
cargo_args+=("--features tdx") cargo_args+=("--features tdx")

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

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

@@ -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;
@@ -59,18 +57,10 @@ 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}")]
EventMonitorIo(std::io::Error), EventMonitorIo(std::io::Error),
#[error("Event monitor thread failed: {0}")]
EventMonitorThread(#[source] vmm::Error),
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
#[error("Error parsing --gdb: {0}")] #[error("Error parsing --gdb: {0}")]
ParsingGdb(option_parser::OptionParserError), ParsingGdb(option_parser::OptionParserError),
@@ -148,19 +138,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")]
@@ -180,27 +170,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\")")]
@@ -208,31 +198,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(switch, long = "pvpanic")]
/// enable pvpanic device
pvpanic: bool,
#[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")]
@@ -251,27 +237,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\")")]
@@ -284,7 +255,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")]
@@ -355,9 +326,6 @@ impl TopLevel {
}; };
let vsock = self.vsock.as_deref(); let vsock = self.vsock.as_deref();
let pvpanic = self.pvpanic;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
let sgx_epc = if !self.sgx_epc.is_empty() { let sgx_epc = if !self.sgx_epc.is_empty() {
Some(self.sgx_epc.iter().map(|x| x.as_str()).collect()) Some(self.sgx_epc.iter().map(|x| x.as_str()).collect())
@@ -396,7 +364,6 @@ impl TopLevel {
user_devices, user_devices,
vdpa, vdpa,
vsock, vsock,
pvpanic,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
sgx_epc, sgx_epc,
numa, numa,
@@ -449,22 +416,36 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
(None, None) (None, None)
}; };
#[cfg(feature = "dbus_api")] if let Some(ref monitor_config) = toplevel.event_monitor {
let dbus_options = match (&toplevel.dbus_name, &toplevel.dbus_path) { let mut parser = OptionParser::new();
(Some(ref name), Some(ref path)) => Ok(Some(DBusApiOptions { parser.add("path").add("fd");
service_name: name.to_owned(), parser
object_path: path.to_owned(), .parse(monitor_config)
system_bus: toplevel.dbus_system_bus, .map_err(Error::ParsingEventMonitor)?;
})),
(Some(_), None) => Err(Error::MissingDBusObjectPath), let file = if parser.is_set("fd") {
(None, Some(_)) => Err(Error::MissingDBusServiceName), let fd = parser
(None, None) => Ok(None), .convert("fd")
}?; .map_err(Error::ParsingEventMonitor)?
.unwrap();
// SAFETY: fd is valid
unsafe { File::from_raw_fd(fd) }
} else if parser.is_set("path") {
std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(parser.get("path").unwrap())
.map_err(Error::EventMonitorIo)?
} else {
return Err(Error::BareEventMonitor);
};
event_monitor::set_monitor(file).map_err(Error::EventMonitorIo)?;
}
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,
@@ -507,6 +488,8 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
} }
} }
event!("vmm", "starting");
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?; let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
#[cfg(feature = "guest_debug")] #[cfg(feature = "guest_debug")]
@@ -530,50 +513,12 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?; let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
if let Some(ref monitor_config) = toplevel.event_monitor { let vmm_thread = vmm::start_vmm_thread(
let mut parser = OptionParser::new(); env!("CARGO_PKG_VERSION").to_string(),
parser.add("path").add("fd");
parser
.parse(monitor_config)
.map_err(Error::ParsingEventMonitor)?;
let file = if parser.is_set("fd") {
let fd = parser
.convert("fd")
.map_err(Error::ParsingEventMonitor)?
.unwrap();
// SAFETY: fd is valid
unsafe { File::from_raw_fd(fd) }
} else if parser.is_set("path") {
std::fs::OpenOptions::new()
.write(true)
.create(true)
.open(parser.get("path").unwrap())
.map_err(Error::EventMonitorIo)?
} else {
return Err(Error::BareEventMonitor);
};
let monitor = event_monitor::set_monitor(file).map_err(Error::EventMonitorIo)?;
vmm::start_event_monitor_thread(
monitor,
&seccomp_action,
hypervisor.hypervisor_type(),
exit_evt.try_clone().unwrap(),
)
.map_err(Error::EventMonitorThread)?;
}
event!("vmm", "starting");
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,
@@ -623,17 +568,11 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
} }
} }
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")]
if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
dbus_api_graceful_shutdown(chs);
}
r.map(|_| api_socket_path) r.map(|_| api_socket_path)
} }
@@ -648,7 +587,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;
} }
@@ -791,7 +730,6 @@ mod unit_tests {
user_devices: None, user_devices: None,
vdpa: None, vdpa: None,
vsock: None, vsock: None,
pvpanic: false,
iommu: false, iommu: false,
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
sgx_epc: None, sgx_epc: None,
@@ -809,7 +747,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_cpus() { fn test_valid_vm_config_cpus() {
[ vec![
( (
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
@@ -927,7 +865,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_kernel() { fn test_valid_vm_config_kernel() {
[( vec![(
vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"], vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
r#"{ r#"{
"payload": {"kernel": "/path/to/kernel"} "payload": {"kernel": "/path/to/kernel"}
@@ -942,7 +880,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_cmdline() { fn test_valid_vm_config_cmdline() {
[( vec![(
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
"--kernel", "--kernel",
@@ -963,7 +901,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_disks() { fn test_valid_vm_config_disks() {
[ vec![
( (
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
@@ -1237,7 +1175,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_rng() { fn test_valid_vm_config_rng() {
[( vec![(
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
"--kernel", "--kernel",
@@ -1259,7 +1197,8 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_fs() { fn test_valid_vm_config_fs() {
[( vec![
(
vec![ vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel", "cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--memory", "shared=true",
@@ -1329,7 +1268,8 @@ mod unit_tests {
] ]
}"#, }"#,
true, true,
)] ),
]
.iter() .iter()
.for_each(|(cli, openapi, equal)| { .for_each(|(cli, openapi, equal)| {
compare_vm_config_cli_vs_json(cli, openapi, *equal); compare_vm_config_cli_vs_json(cli, openapi, *equal);
@@ -1338,7 +1278,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_pmem() { fn test_valid_vm_config_pmem() {
[ vec![
( (
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
@@ -1402,7 +1342,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_serial_console() { fn test_valid_vm_config_serial_console() {
[ vec![
( (
vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"], vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
r#"{ r#"{
@@ -1453,7 +1393,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_serial_pty_console_pty() { fn test_valid_vm_config_serial_pty_console_pty() {
[ vec![
( (
vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"], vec!["cloud-hypervisor", "--kernel", "/path/to/kernel"],
r#"{ r#"{
@@ -1601,7 +1541,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_vdpa() { fn test_valid_vm_config_vdpa() {
[ vec![
( (
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
@@ -1648,7 +1588,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_vsock() { fn test_valid_vm_config_vsock() {
[ vec![
( (
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
@@ -1731,7 +1671,7 @@ mod unit_tests {
#[test] #[test]
fn test_valid_vm_config_tpm_socket() { fn test_valid_vm_config_tpm_socket() {
[( vec![(
vec![ vec![
"cloud-hypervisor", "cloud-hypervisor",
"--kernel", "--kernel",

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.3" epoll = "4.3.1"
libc = "0.2.139" libc = "0.2.139"
once_cell = "1.18.0" 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.95"
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"

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