Compare commits

..

4 Commits

Author SHA1 Message Date
Rob Bradford
f6557acf60 build: Release v22.1 (bug fix release)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-03-11 08:44:17 +00:00
Rob Bradford
4d041bd603 virtio-devices: Enable F_EVENT_IDX on control queue if negotiated
With the VIRTIO_F_EVENT_IDX handling now conducted inside the
virtio-queue crate it is necessary to activate the functionality on
every queue if it is negotiatated. Otherwise this leads to a failure of
the guest to signal to the host that there is something in the available
queue as the queue's internal state has not been configured correctly.

Fixes: #3829

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
(cherry picked from commit 223d0cf787)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-03-11 08:44:17 +00:00
Yi Wang
e0fda7bef9 vmm: interrupt: fix msi mask irq causing kernel panic on AMD
When mask a msi irq, we set the entry.masked to be true, so kvm
hypervisor will not pass the gsi to kernel through KVM_SET_GSI_ROUTING
ioctl which update kvm->irq_routing. This will trigger kernel
panic on AMD platform when the gsi is the largest one in kernel
kvm->irqfds.items:

crash> bt
PID: 22218  TASK: ffff951a6ad74980  CPU: 73  COMMAND: "vcpu8"
 #0 [ffffb1ba6707fa40] machine_kexec at ffffffff8565b397
 #1 [ffffb1ba6707fa90] __crash_kexec at ffffffff85788a6d
 #2 [ffffb1ba6707fb58] crash_kexec at ffffffff8578995d
 #3 [ffffb1ba6707fb70] oops_end at ffffffff85623c0d
 #4 [ffffb1ba6707fb90] no_context at ffffffff856692c9
 #5 [ffffb1ba6707fbf8] exc_page_fault at ffffffff85f95b51
 #6 [ffffb1ba6707fc50] asm_exc_page_fault at ffffffff86000ace
    [exception RIP: svm_update_pi_irte+227]
    RIP: ffffffffc0761b53  RSP: ffffb1ba6707fd08  RFLAGS: 00010086
    RAX: ffffb1ba6707fd78  RBX: ffffb1ba66d91000  RCX: 0000000000000001
    RDX: 00003c803f63f1c0  RSI: 000000000000019a  RDI: ffffb1ba66db2ab8
    RBP: 000000000000019a   R8: 0000000000000040   R9: ffff94ca41b82200
    R10: ffffffffffffffcf  R11: 0000000000000001  R12: 0000000000000001
    R13: 0000000000000001  R14: ffffffffffffffcf  R15: 000000000000005f
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
 #7 [ffffb1ba6707fdb8] kvm_irq_routing_update at ffffffffc09f19a1 [kvm]
 #8 [ffffb1ba6707fde0] kvm_set_irq_routing at ffffffffc09f2133 [kvm]
 #9 [ffffb1ba6707fe18] kvm_vm_ioctl at ffffffffc09ef544 [kvm]
    RIP: 00007f143c36488b  RSP: 00007f143a4e04b8  RFLAGS: 00000246
    RAX: ffffffffffffffda  RBX: 00007f05780041d0  RCX: 00007f143c36488b
    RDX: 00007f05780041d0  RSI: 000000004008ae6a  RDI: 0000000000000020
    RBP: 00000000000004e8   R8: 0000000000000008   R9: 00007f05780041e0
    R10: 00007f0578004560  R11: 0000000000000246  R12: 00000000000004e0
    R13: 000000000000001a  R14: 00007f1424001c60  R15: 00007f0578003bc0
    ORIG_RAX: 0000000000000010  CS: 0033  SS: 002b

To solve this problem, move route.disable() before set_gsi_routes() to
remove the gsi from irqfds.items first.

This problem only exists on AMD platform, 'cause on Intel platform
kernel just return when update irte while it only prints a warning on
AMD.

Also, this patch adjusts the order of enable() and set_gsi_routes() in
unmask(), which should do no harm.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
(cherry picked from commit 5375b84e3b)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-03-11 08:44:17 +00:00
Yi Wang
9e2d051237 vmm: interrupt: fix msi mask irq causing kernel panic on AMD
When mask a msi irq, we set the entry.masked to be true, so kvm
hypervisor will not pass the gsi to kernel through KVM_SET_GSI_ROUTING
ioctl which update kvm->irq_routing. This will trigger kernel
panic on AMD platform when the gsi is the largest one in kernel
kvm->irqfds.items:

crash> bt
PID: 22218  TASK: ffff951a6ad74980  CPU: 73  COMMAND: "vcpu8"
 #0 [ffffb1ba6707fa40] machine_kexec at ffffffff8565b397
 #1 [ffffb1ba6707fa90] __crash_kexec at ffffffff85788a6d
 #2 [ffffb1ba6707fb58] crash_kexec at ffffffff8578995d
 #3 [ffffb1ba6707fb70] oops_end at ffffffff85623c0d
 #4 [ffffb1ba6707fb90] no_context at ffffffff856692c9
 #5 [ffffb1ba6707fbf8] exc_page_fault at ffffffff85f95b51
 #6 [ffffb1ba6707fc50] asm_exc_page_fault at ffffffff86000ace
    [exception RIP: svm_update_pi_irte+227]
    RIP: ffffffffc0761b53  RSP: ffffb1ba6707fd08  RFLAGS: 00010086
    RAX: ffffb1ba6707fd78  RBX: ffffb1ba66d91000  RCX: 0000000000000001
    RDX: 00003c803f63f1c0  RSI: 000000000000019a  RDI: ffffb1ba66db2ab8
    RBP: 000000000000019a   R8: 0000000000000040   R9: ffff94ca41b82200
    R10: ffffffffffffffcf  R11: 0000000000000001  R12: 0000000000000001
    R13: 0000000000000001  R14: ffffffffffffffcf  R15: 000000000000005f
    ORIG_RAX: ffffffffffffffff  CS: 0010  SS: 0018
 #7 [ffffb1ba6707fdb8] kvm_irq_routing_update at ffffffffc09f19a1 [kvm]
 #8 [ffffb1ba6707fde0] kvm_set_irq_routing at ffffffffc09f2133 [kvm]
 #9 [ffffb1ba6707fe18] kvm_vm_ioctl at ffffffffc09ef544 [kvm]
    RIP: 00007f143c36488b  RSP: 00007f143a4e04b8  RFLAGS: 00000246
    RAX: ffffffffffffffda  RBX: 00007f05780041d0  RCX: 00007f143c36488b
    RDX: 00007f05780041d0  RSI: 000000004008ae6a  RDI: 0000000000000020
    RBP: 00000000000004e8   R8: 0000000000000008   R9: 00007f05780041e0
    R10: 00007f0578004560  R11: 0000000000000246  R12: 00000000000004e0
    R13: 000000000000001a  R14: 00007f1424001c60  R15: 00007f0578003bc0
    ORIG_RAX: 0000000000000010  CS: 0033  SS: 002b

To solve this problem, move route.disable() before set_gsi_routes() to
remove the gsi from irqfds.items first.

This problem only exists on AMD platform, 'cause on Intel platform
kernel just return when update irte while it only prints a warning on
AMD.

Signed-off-by: Yi Wang <wang.yi59@zte.com.cn>
(cherry picked from commit db9e5e5a87)
Signed-off-by: Rob Bradford <robert.bradford@intel.com>
2022-03-11 08:44:17 +00:00
128 changed files with 2082 additions and 4482 deletions

View File

@@ -4,7 +4,7 @@ updates:
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 1
open-pull-requests-limit: 3
allow:
- dependency-type: direct
- dependency-type: indirect
@@ -12,7 +12,7 @@ updates:
directory: "/fuzz"
schedule:
interval: daily
open-pull-requests-limit: 1
open-pull-requests-limit: 3
allow:
- dependency-type: direct
- dependency-type: indirect

View File

@@ -13,7 +13,7 @@ jobs:
- stable
- beta
- nightly
- 1.56
- 1.54
target:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
@@ -35,27 +35,24 @@ jobs:
- name: Debug Check (default features)
run: |
git rev-list origin/main..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --tests --all --target=${{ matrix.target }}'
git rev-list origin/main..$GITHUB_SHA | xargs -t -I % sh -c 'git checkout %; cargo check --all --target=${{ matrix.target }}'
git checkout $GITHUB_SHA
- name: Build (default features)
run: cargo rustc --bin cloud-hypervisor -- -D warnings
- name: Build (common + kvm)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,kvm" -- -D warnings
- name: Build (default features + tdx)
- name: Build (default + tdx)
run: cargo rustc --bin cloud-hypervisor --features "tdx" -- -D warnings
- name: Build (default features + amx)
run: cargo rustc --bin cloud-hypervisor --features "amx" -- -D warnings
- name: Build (acpi,kvm)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "acpi,kvm" -- -D warnings
- name: Build (default features + gdb)
run: cargo rustc --bin cloud-hypervisor --features "gdb" -- -D warnings
- name: Build (kvm)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "kvm" -- -D warnings
- name: Build (common + mshv)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "common,mshv" -- -D warnings
- name: Build (acpi,mshv)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "acpi,mshv" -- -D warnings
- name: Build (mshv)
run: cargo rustc --bin cloud-hypervisor --no-default-features --features "mshv" -- -D warnings
- name: Release Build (default features)
run: cargo build --all --release --target=${{ matrix.target }}

View File

@@ -32,16 +32,30 @@ jobs:
- name: Formatting (rustfmt)
run: cargo fmt -- --check
- name: Clippy (common + kvm)
- name: Clippy (kvm)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: clippy
args: --target=${{ matrix.target }} --tests --all --no-default-features --features "common,kvm" -- -D warnings
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm" -- -D warnings
- name: Clippy (default features)
- name: Clippy (kvm,acpi)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: clippy
args: --target=${{ matrix.target }} --tests --all -- -D warnings
args: --target=${{ matrix.target }} --all --no-default-features --features "kvm,acpi" -- -D warnings
- name: Clippy (all features,kvm)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: clippy
args: --target=${{ matrix.target }} --all --no-default-features --features "common,kvm" -- -D warnings
- name: Clippy (default)
uses: actions-rs/cargo@v1
with:
use-cross: true
command: clippy
args: --target=${{ matrix.target }} --all -- -D warnings

View File

@@ -33,20 +33,29 @@ jobs:
- name: Formatting (rustfmt)
run: cargo fmt -- --check
- name: Clippy (common + kvm)
- name: Clippy (all features,kvm)
run: cargo clippy --all --all-targets --no-default-features --tests --features "common,kvm" -- -D warnings
- name: Clippy (default features)
run: cargo clippy --all --all-targets --tests -- -D warnings
- name: Clippy (default features + amx)
run: cargo clippy --all --all-targets --tests --features "amx" -- -D warnings
- name: Clippy (default features + gdb)
run: cargo clippy --all --all-targets --tests --features "gdb" -- -D warnings
- name: Clippy (common + mshv)
- name: Clippy (all features,mshv)
run: cargo clippy --all --all-targets --no-default-features --tests --features "common,mshv" -- -D warnings
- name: Clippy (acpi,kvm)
run: cargo clippy --all --all-targets --no-default-features --tests --features "acpi,kvm" -- -D warnings
- name: Clippy (acpi,kvm,tdx)
run: cargo clippy --all --all-targets --no-default-features --tests --features "acpi,kvm,tdx" -- -D warnings
- name: Clippy (kvm)
run: cargo clippy --all --all-targets --no-default-features --tests --features "kvm" -- -D warnings
- name: Clippy (acpi,mshv)
run: cargo clippy --all --all-targets --no-default-features --tests --features "acpi,mshv" -- -D warnings
- name: Clippy (mshv)
run: cargo clippy --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings
- name: Clippy (integration tests)
run: cargo clippy --all --all-targets --tests -- -D warnings
- name: Check build did not modify any files
run: test -z "$(git status --porcelain)"

View File

@@ -16,31 +16,23 @@ jobs:
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
uses: actions-rs/toolchain@v1
with:
toolchain: 1.58
toolchain: stable
target: x86_64-unknown-linux-gnu
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: 1.58
toolchain: stable
target: x86_64-unknown-linux-musl
- name: Build
uses: actions-rs/cargo@v1
with:
toolchain: 1.58
command: build
args: --all --release --target=x86_64-unknown-linux-gnu
run: cargo build --all --release --target=x86_64-unknown-linux-gnu
- name: Static Build
uses: actions-rs/cargo@v1
with:
toolchain: 1.58
command: build
args: --all --release --target=x86_64-unknown-linux-musl
run: cargo build --all --release --target=x86_64-unknown-linux-musl
- name: Strip cloud-hypervisor binaries
run: strip target/*/release/cloud-hypervisor
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
uses: actions-rs/toolchain@v1
with:
toolchain: 1.58
toolchain: stable
target: aarch64-unknown-linux-musl
override: true
- name: Static Build (AArch64)

View File

@@ -1 +1 @@
edition = "2021"
edition = "2018"

103
Cargo.lock generated
View File

@@ -20,9 +20,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.56"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
[[package]]
name = "api_client"
@@ -131,9 +131,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.1.8"
version = "3.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
dependencies = [
"atty",
"bitflags",
@@ -148,7 +148,7 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "23.1.0"
version = "22.1.0"
dependencies = [
"anyhow",
"api_client",
@@ -175,9 +175,9 @@ dependencies = [
[[package]]
name = "crc32c"
version = "0.6.3"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfea2db42e9927a3845fb268a10a72faed6d416065f77873f05e411457c363e"
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
dependencies = [
"rustc_version",
]
@@ -219,9 +219,9 @@ dependencies = [
[[package]]
name = "dirs-sys"
version = "0.3.7"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
dependencies = [
"libc",
"redox_users",
@@ -293,9 +293,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
@@ -363,9 +363,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.8.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
@@ -433,9 +433,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.123"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "libssh2-sys"
@@ -453,9 +453,9 @@ dependencies = [
[[package]]
name = "libz-sys"
version = "1.1.5"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f35facd4a5673cb5a48822be2be1d4236c1c99cb4113cab7061ac720d5bf859"
checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
dependencies = [
"cc",
"libc",
@@ -474,19 +474,18 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.7"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53"
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.16"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
@@ -515,7 +514,7 @@ dependencies = [
[[package]]
name = "mshv-bindings"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
source = "git+https://github.com/rust-vmm/mshv?branch=main#d241ffcacdfa4240b4a1d34b44af89dc7b113986"
dependencies = [
"libc",
"serde",
@@ -527,7 +526,7 @@ dependencies = [
[[package]]
name = "mshv-ioctls"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/mshv?branch=main#75cf309d566c3d9ba91e81582a7864032ecc5bbb"
source = "git+https://github.com/rust-vmm/mshv?branch=main#d241ffcacdfa4240b4a1d34b44af89dc7b113986"
dependencies = [
"libc",
"mshv-bindings",
@@ -575,9 +574,9 @@ dependencies = [
[[package]]
name = "openssl-src"
version = "111.18.0+1.1.1n"
version = "111.17.0+1.1.1m"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7897a926e1e8d00219127dc020130eca4292e5ca666dd592480d72c3eca2ff6c"
checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
dependencies = [
"cc",
]
@@ -636,9 +635,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.7"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
[[package]]
name = "pci"
@@ -680,9 +679,9 @@ dependencies = [
[[package]]
name = "pkg-config"
version = "0.3.25"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
[[package]]
name = "pnet"
@@ -774,9 +773,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.37"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
@@ -794,9 +793,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.18"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
@@ -812,29 +811,28 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.2.13"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_users"
version = "0.4.3"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
"getrandom",
"redox_syscall",
"thiserror",
]
[[package]]
name = "regex"
version = "1.5.5"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
@@ -890,9 +888,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.7"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
[[package]]
name = "serde"
@@ -973,9 +971,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.91"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
@@ -1162,9 +1160,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.4.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53567fd9ab820e4f3cc156f24146882fee3c365194c3e1dea74723265f27fc88"
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
dependencies = [
"bitflags",
"libc",
@@ -1174,9 +1172,8 @@ dependencies = [
[[package]]
name = "vhost-user-backend"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1490f2028d4f119b2292efe218b5f8cfc6471f039b53b6a6eb5d9513e964facc"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vhost-user-backend?branch=main#bbc892ba4526bdf8101252f7aa51832d1f2eeabd"
dependencies = [
"libc",
"log",
@@ -1251,7 +1248,6 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"thiserror",
"versionize",
"versionize_derive",
"vhost",
@@ -1267,9 +1263,8 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vm-virtio?branch=main#bbb22d43558a76cc7cc9c262c4be870a9e682a86"
dependencies = [
"log",
"vm-memory",

View File

@@ -1,8 +1,8 @@
[package]
name = "cloud-hypervisor"
version = "23.1.0"
version = "22.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
default-run = "cloud-hypervisor"
build = "build.rs"
license = "LICENSE-APACHE & LICENSE-BSD-3-Clause"
@@ -10,20 +10,20 @@ description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
# Minimum buildable version:
# Keep in sync with version in .github/workflows/build.yaml
rust-version = "1.56"
rust-version = "1.54"
[profile.release]
lto = true
[dependencies]
anyhow = "1.0.56"
anyhow = "1.0.55"
api_client = { path = "api_client" }
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
clap = { version = "3.1.5", features = ["wrap_help","cargo"] }
epoll = "4.3.1"
event_monitor = { path = "event_monitor" }
hypervisor = { path = "hypervisor" }
libc = "0.2.123"
log = { version = "0.4.16", features = ["std"] }
libc = "0.2.119"
log = { version = "0.4.14", features = ["std"] }
option_parser = { path = "option_parser" }
seccompiler = "0.2.0"
serde_json = "1.0.79"
@@ -34,13 +34,14 @@ vmm-sys-util = "0.9.0"
vm-memory = "0.7.0"
[build-dependencies]
clap = { version = "3.1.8", features = ["cargo"] }
clap = { version = "3.1.5", features = ["wrap_help"] }
# List of patched crates
[patch.crates-io]
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
[dev-dependencies]
dirs = "4.0.0"
@@ -53,8 +54,8 @@ wait-timeout = "0.2.0"
[features]
default = ["common", "kvm"]
# Common features for all hypervisors
common = ["fwdebug"]
amx = ["vmm/amx"]
common = ["acpi", "cmos", "fwdebug"]
acpi = ["vmm/acpi"]
cmos = ["vmm/cmos"]
fwdebug = ["vmm/fwdebug"]
gdb = ["vmm/gdb"]
@@ -78,7 +79,6 @@ members = [
"performance-metrics",
"qcow",
"rate_limiter",
"test_infra",
"vfio_user",
"vhdx",
"vhost_user_block",

22
Jenkinsfile vendored
View File

@@ -43,7 +43,7 @@ pipeline{
stage ('Build') {
parallel {
stage ('Worker build') {
agent { node { label 'focal' } }
agent { node { label 'hirsute' } }
when {
beforeAgent true
expression {
@@ -56,11 +56,7 @@ pipeline{
checkout scm
}
}
stage ('Prepare environment') {
steps {
sh "scripts/prepare_vdpa.sh"
}
}
stage ('Run OpenAPI tests') {
steps {
sh "scripts/run_openapi_tests.sh"
@@ -119,7 +115,7 @@ pipeline{
}
}
stage ('Worker build (musl)') {
agent { node { label 'focal' } }
agent { node { label 'hirsute' } }
when {
beforeAgent true
expression {
@@ -132,11 +128,7 @@ pipeline{
checkout scm
}
}
stage ('Prepare environment') {
steps {
sh "scripts/prepare_vdpa.sh"
}
}
stage ('Run unit tests for musl') {
steps {
sh "scripts/dev_cli.sh tests --unit --libc musl"
@@ -236,7 +228,7 @@ pipeline{
}
}
stage ('Worker build - Windows guest') {
agent { node { label 'focal' } }
agent { node { label 'hirsute' } }
when {
beforeAgent true
expression {
@@ -282,7 +274,7 @@ pipeline{
}
}
stage ('Worker build - Live Migration') {
agent { node { label 'focal-small' } }
agent { node { label 'hirsute-small' } }
when {
beforeAgent true
expression {
@@ -387,7 +379,7 @@ def cancelPreviousBuilds() {
def installAzureCli() {
sh "sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg"
sh "curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null"
sh "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ focal main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
sh "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ hirsute main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
sh "sudo apt update"
sh "sudo apt install -y azure-cli"
}

View File

@@ -267,26 +267,26 @@ Cloud Hypervisor is under active development. The following stability guarantees
are currently made:
* The API (including command line options) will not be removed or changed in a
breaking way without a minimum of 2 major releases notice. Where possible
warnings will be given about the use of deprecated functionality and the
deprecations will be documented in the release notes.
breaking way without a minimum of 2 releases notice. Where possible warnings
will be given about the use of deprecated functionality and the deprecations
will be documented in the release notes.
* Point releases will be made between individual releases where there are
substantial bug fixes or security issues that need to be fixed. These point
releases will only include bug fixes.
substantial bug fixes or security issues that need to be fixed.
Currently the following items are **not** guaranteed across updates:
* Snapshot/restore is not supported across different versions
* Live migration is not supported across different versions
* The following features are considered experimental and may change
substantially between releases: TDX, vfio-user, vDPA.
substantially between releases: TDX, SGX.
As of 2022-04-05, the following cloud images are supported:
As of 2021-04-29, the following cloud images are supported:
- [Ubuntu Bionic](https://cloud-images.ubuntu.com/bionic/current/) (cloudimg)
- [Ubuntu Focal](https://cloud-images.ubuntu.com/focal/current/) (cloudimg)
- [Ubuntu Jammy](https://cloud-images.ubuntu.com/jammy/current/) (cloudimg)
- [Ubuntu Groovy](https://cloud-images.ubuntu.com/groovy/current/) (cloudimg)
- [Ubuntu Hirsute](https://cloud-images.ubuntu.com/hirsute/current/) (cloudimg)
Direct kernel boot to userspace should work with a rootfs from most
distributions.

View File

@@ -2,7 +2,7 @@
name = "acpi_tables"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
vm-memory = "0.7.0"

View File

@@ -2,7 +2,7 @@
name = "api_client"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
vmm-sys-util = "0.9.0"

View File

@@ -2,20 +2,21 @@
name = "arch"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
edition = "2018"
[features]
default = []
acpi = ["acpi_tables"]
tdx = []
[dependencies]
acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.56"
acpi_tables = { path = "../acpi_tables", optional = true }
anyhow = "1.0.55"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
libc = "0.2.123"
libc = "0.2.119"
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
log = "0.4.16"
log = "0.4.14"
serde = { version = "1.0.136", features = ["rc"] }
serde_derive = "1.0.136"
thiserror = "1.0.30"

View File

@@ -18,13 +18,14 @@ use std::str;
use super::super::DeviceType;
use super::super::GuestMemoryMmap;
use super::super::InitramfsConfig;
use super::get_fdt_addr;
use super::gic::GicDevice;
use super::layout::{
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
};
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion};
// This is a value for uniquely identifying the FDT node declaring the interrupt controller.
const GIC_PHANDLE: u32 = 1;
@@ -140,8 +141,9 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> Result<()> {
// Write FDT to memory.
let fdt_address = GuestAddress(get_fdt_addr());
guest_mem
.write_slice(fdt_final.as_slice(), super::layout::FDT_START)
.write_slice(fdt_final.as_slice(), fdt_address)
.map_err(Error::WriteFdtToMemory)?;
Ok(())
}
@@ -229,67 +231,40 @@ fn create_memory_node(
guest_mem: &GuestMemoryMmap,
numa_nodes: &NumaNodes,
) -> FdtWriterResult<()> {
// See https://github.com/torvalds/linux/blob/58ae0b51506802713aa0e9956d1853ba4c722c98/Documentation/devicetree/bindings/numa.txt
// for NUMA setting in memory node.
if numa_nodes.len() > 1 {
for numa_node_idx in 0..numa_nodes.len() {
let numa_node = numa_nodes.get(&(numa_node_idx as u32));
let mut mem_reg_prop: Vec<u64> = Vec::new();
let mut node_memory_addr: u64 = 0;
// Each memory zone of numa will have its own memory node, but
// different numa nodes should not share same memory zones.
for memory_region in numa_node.unwrap().memory_regions.iter() {
let memory_region_start_addr: u64 = memory_region.start_addr().raw_value();
let memory_region_size: u64 = memory_region.size() as u64;
mem_reg_prop.push(memory_region_start_addr);
mem_reg_prop.push(memory_region_size);
// Set the node address the first non-zero regison address
if node_memory_addr == 0 {
node_memory_addr = memory_region_start_addr;
let mem_reg_prop = [memory_region_start_addr, memory_region_size];
// With feature `acpi` enabled, RAM at 0-4M is for edk2 only
// and should be hidden to the guest.
#[cfg(feature = "acpi")]
if memory_region_start_addr == 0 {
continue;
}
let memory_node_name = format!("memory@{:x}", memory_region_start_addr);
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.property_u32("numa-node-id", numa_node_idx as u32)?;
fdt.end_node(memory_node)?;
}
let memory_node_name = format!("memory@{:x}", node_memory_addr);
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.property_u32("numa-node-id", numa_node_idx as u32)?;
fdt.end_node(memory_node)?;
}
} else {
let last_addr = guest_mem.last_addr().raw_value();
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
// Case 1: all RAM is under the hole
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let memory_node = fdt.begin_node("memory")?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
} else {
// Case 2: RAM is split by the hole
// Region 1: RAM before the hole
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
- super::layout::RAM_START.raw_value();
let mem_reg_prop = [super::layout::RAM_START.raw_value() as u64, mem_size as u64];
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
let mem_size = guest_mem.last_addr().raw_value() - super::layout::RAM_64BIT_START + 1;
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
// for an explanation of this.
let mem_reg_prop = [super::layout::RAM_64BIT_START as u64, mem_size as u64];
let memory_node = fdt.begin_node("memory")?;
// Region 2: RAM after the hole
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
let mem_reg_prop = [
super::layout::RAM_64BIT_START.raw_value() as u64,
mem_size as u64,
];
let memory_node_name =
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
let memory_node = fdt.begin_node(&memory_node_name)?;
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
}
fdt.property_string("device_type", "memory")?;
fdt.property_array_u64("reg", &mem_reg_prop)?;
fdt.end_node(memory_node)?;
}
Ok(())
@@ -573,19 +548,20 @@ fn create_pci_nodes(
// could fall bellow 4G.
// Here we cut off PCI device space below 8G in FDT to workaround the EDK2 check.
// But the address written in ACPI is not impacted.
let (pci_device_base_64bit, pci_device_size_64bit) =
if pci_device_info_elem.pci_device_space_start < PCI_HIGH_BASE.raw_value() {
(
PCI_HIGH_BASE.raw_value(),
pci_device_info_elem.pci_device_space_size
- (PCI_HIGH_BASE.raw_value() - pci_device_info_elem.pci_device_space_start),
)
} else {
(
pci_device_info_elem.pci_device_space_start,
pci_device_info_elem.pci_device_space_size,
)
};
let (pci_device_base_64bit, pci_device_size_64bit) = if cfg!(feature = "acpi")
&& (pci_device_info_elem.pci_device_space_start < PCI_HIGH_BASE)
{
(
PCI_HIGH_BASE,
pci_device_info_elem.pci_device_space_size
- (PCI_HIGH_BASE - pci_device_info_elem.pci_device_space_start),
)
} else {
(
pci_device_info_elem.pci_device_space_start,
pci_device_info_elem.pci_device_space_size,
)
};
// There is no specific requirement of the 32bit MMIO range, and
// therefore at least we can make these ranges 4K aligned.
let pci_device_size_32bit: u64 =

View File

@@ -22,7 +22,6 @@ pub mod kvm {
use std::{boxed::Box, result};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use vm_memory::Address;
use vm_migration::{
Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable,
VersionMapped,
@@ -84,7 +83,7 @@ pub mod kvm {
/// Get the address of the GIC distributor.
pub fn get_dist_addr() -> u64 {
layout::GIC_V3_DIST_START.raw_value()
layout::GIC_V3_DIST_START
}
/// Get the size of the GIC distributor.

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0
//
// Memory layout of AArch64 guest:
// Memory layout of Aarch64 guest:
//
// Physical +---------------------------------------------------------------+
// address | |
@@ -20,13 +20,6 @@
// | DRAM |
// | |
// | |
// 4GB +---------------------------------------------------------------+
// | 32-bit devices hole |
// 4GB-64M +---------------------------------------------------------------+
// | |
// | |
// | DRAM |
// | |
// | |
// 1GB +---------------------------------------------------------------+
// | |
@@ -42,11 +35,11 @@
// | Legacy devices space |
// | |
// 144 M +---------------------------------------------------------------|
// | |
// | Reserved (now GIC is here) |
// 64 M +---------------------------------------------------------------+
// | |
// | UEFI space |
// | |
// 4 M +---------------------------------------------------------------+
// | UEFI flash |
// 0GB +---------------------------------------------------------------+
//
//
@@ -55,16 +48,17 @@ use vm_memory::GuestAddress;
/// 0x0 ~ 0x40_0000 (4 MiB) is reserved to UEFI
/// UEFI binary size is required less than 3 MiB, reserving 4 MiB is enough.
pub const UEFI_START: GuestAddress = GuestAddress(0);
pub const UEFI_START: u64 = 0x0;
pub const MEM_UEFI_START: GuestAddress = GuestAddress(0);
pub const UEFI_SIZE: u64 = 0x040_0000;
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
pub const MAPPED_IO_START: GuestAddress = GuestAddress(0x0900_0000);
pub const MAPPED_IO_START: u64 = 0x0900_0000;
/// See kernel file arch/arm64/include/uapi/asm/kvm.h for the GIC related definitions.
/// 0x08ff_0000 ~ 0x0900_0000 is reserved for GICv3 Distributor
pub const GIC_V3_DIST_SIZE: u64 = 0x01_0000;
pub const GIC_V3_DIST_START: GuestAddress = GuestAddress(MAPPED_IO_START.0 - GIC_V3_DIST_SIZE);
pub const GIC_V3_DIST_START: u64 = MAPPED_IO_START - GIC_V3_DIST_SIZE;
/// Below 0x08ff_0000 is reserved for GICv3 Redistributor.
/// The size defined here is for each vcpu.
/// The total size is 'number_of_vcpu * GIC_V3_REDIST_SIZE'
@@ -73,9 +67,9 @@ pub const GIC_V3_REDIST_SIZE: u64 = 0x02_0000;
pub const GIC_V3_ITS_SIZE: u64 = 0x02_0000;
/// Space 0x0900_0000 ~ 0x0905_0000 is reserved for legacy devices.
pub const LEGACY_SERIAL_MAPPED_IO_START: GuestAddress = GuestAddress(0x0900_0000);
pub const LEGACY_RTC_MAPPED_IO_START: GuestAddress = GuestAddress(0x0901_0000);
pub const LEGACY_GPIO_MAPPED_IO_START: GuestAddress = GuestAddress(0x0902_0000);
pub const LEGACY_SERIAL_MAPPED_IO_START: u64 = 0x0900_0000;
pub const LEGACY_RTC_MAPPED_IO_START: u64 = 0x0901_0000;
pub const LEGACY_GPIO_MAPPED_IO_START: u64 = 0x0902_0000;
/// Space 0x0905_0000 ~ 0x0906_0000 is reserved for pcie io address
pub const MEM_PCI_IO_START: GuestAddress = GuestAddress(0x0905_0000);
@@ -91,15 +85,8 @@ pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
// One bus with potentially 256 devices (32 slots x 8 functions).
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
/// Start of RAM.
pub const RAM_START: GuestAddress = GuestAddress(0x4000_0000);
/// 32-bit reserved area: 64MiB before 4GiB
pub const MEM_32BIT_RESERVED_START: GuestAddress = GuestAddress(0xfc00_0000);
pub const MEM_32BIT_RESERVED_SIZE: u64 = 0x0400_0000;
/// Start of 64-bit RAM.
pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000);
/// Start of RAM on 64 bit ARM.
pub const RAM_64BIT_START: u64 = 0x4000_0000;
/// Kernel command line maximum size.
/// As per `arch/arm64/include/uapi/asm/setup.h`.
@@ -107,19 +94,19 @@ pub const CMDLINE_MAX_SIZE: usize = 2048;
/// FDT is at the beginning of RAM.
/// Maximum size of the device tree blob as specified in https://www.kernel.org/doc/Documentation/arm64/booting.txt.
pub const FDT_START: GuestAddress = RAM_START;
pub const FDT_MAX_SIZE: u64 = 0x20_0000;
pub const FDT_START: u64 = RAM_64BIT_START;
pub const FDT_MAX_SIZE: usize = 0x20_0000;
/// Put ACPI table above dtb
pub const ACPI_START: GuestAddress = GuestAddress(RAM_START.0 + FDT_MAX_SIZE);
pub const ACPI_MAX_SIZE: u64 = 0x20_0000;
pub const RSDP_POINTER: GuestAddress = ACPI_START;
pub const ACPI_START: u64 = RAM_64BIT_START + FDT_MAX_SIZE as u64;
pub const ACPI_MAX_SIZE: usize = 0x20_0000;
pub const RSDP_POINTER: GuestAddress = GuestAddress(ACPI_START);
/// Kernel start after FDT and ACPI
pub const KERNEL_START: GuestAddress = GuestAddress(ACPI_START.0 + ACPI_MAX_SIZE);
pub const KERNEL_START: u64 = ACPI_START + ACPI_MAX_SIZE as u64;
/// Pci high memory base
pub const PCI_HIGH_BASE: GuestAddress = GuestAddress(0x2_0000_0000);
pub const PCI_HIGH_BASE: u64 = 0x2_0000_0000_u64;
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
// the number of interrupts our GIC will support to be:

View File

@@ -78,11 +78,31 @@ pub fn configure_vcpu(
}
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
let mut regions = vec![
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
// Normally UEFI should be loaded to a flash area at the beginning of memory.
// But now flash memory type is not supported.
// As a workaround, we take 4 MiB memory from the main RAM for UEFI.
// As a result, the RAM that the guest can see is less than what has been
// assigned in command line, when ACPI and UEFI is enabled.
let ram_deduction = if cfg!(feature = "acpi") {
layout::UEFI_SIZE
} else {
0
};
vec![
// 0 ~ 4 MiB: Reserved for UEFI space
#[cfg(feature = "acpi")]
(GuestAddress(0), layout::UEFI_SIZE as usize, RegionType::Ram),
#[cfg(not(feature = "acpi"))]
(
GuestAddress(0),
layout::MEM_32BIT_DEVICES_START.0 as usize,
layout::UEFI_SIZE as usize,
RegionType::Reserved,
),
// 4 MiB ~ 256 MiB: Gic and legacy devices
(
GuestAddress(layout::UEFI_SIZE),
(layout::MEM_32BIT_DEVICES_START.0 - layout::UEFI_SIZE) as usize,
RegionType::Reserved,
),
// 256 MiB ~ 768 MiB: MMIO space
@@ -97,39 +117,13 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
layout::PCI_MMCONFIG_SIZE as usize,
RegionType::Reserved,
),
];
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
// RAM space
// Case1: guest memory fits before the gap
if size as u64 <= ram_32bit_space_size {
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
// Case2: guest memory extends beyond the gap
} else {
// Push memory before the gap
regions.push((
layout::RAM_START,
ram_32bit_space_size as usize,
// 1 GiB ~ : Ram
(
GuestAddress(layout::RAM_64BIT_START),
(size - ram_deduction) as usize,
RegionType::Ram,
));
// Other memory is placed after 4GiB
regions.push((
layout::RAM_64BIT_START,
(size - ram_32bit_space_size) as usize,
RegionType::Ram,
));
}
// Add the 32-bit reserved memory hole as a reserved region
regions.push((
layout::MEM_32BIT_RESERVED_START,
layout::MEM_32BIT_RESERVED_SIZE as usize,
RegionType::Reserved,
));
regions
),
]
}
/// Configures the system and should be called once per vm before starting vcpu threads.
@@ -192,6 +186,21 @@ pub fn initramfs_load_addr(
}
}
/// Returns the memory address where the kernel could be loaded.
pub fn get_kernel_start() -> u64 {
layout::KERNEL_START
}
///Return guest memory address where the uefi should be loaded.
pub fn get_uefi_start() -> u64 {
layout::UEFI_START
}
// Auxiliary function to get the address where the device tree blob is loaded.
fn get_fdt_addr() -> u64 {
layout::FDT_START
}
pub fn get_host_cpu_phys_bits() -> u8 {
// A dummy hypervisor created only for querying the host IPA size and will
// be freed after the query.
@@ -211,26 +220,11 @@ mod tests {
use super::*;
#[test]
fn test_arch_memory_regions_dram_2gb() {
let regions = arch_memory_regions((1usize << 31) as u64); //2GB
assert_eq!(5, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!((1usize << 31), regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[4].2);
}
#[test]
fn test_arch_memory_regions_dram_4gb() {
fn test_arch_memory_regions_dram() {
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
let ram_32bit_space_size =
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
assert_eq!(6, regions.len());
assert_eq!(layout::RAM_START, regions[3].0);
assert_eq!(ram_32bit_space_size as usize, regions[3].1);
assert_eq!(RegionType::Ram, regions[3].2);
assert_eq!(RegionType::Reserved, regions[5].2);
assert_eq!(5, regions.len());
assert_eq!(GuestAddress(layout::RAM_64BIT_START), regions[4].0);
assert_eq!(1usize << 32, regions[4].1);
assert_eq!(RegionType::Ram, regions[4].2);
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
}
}

View File

@@ -5,13 +5,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.
use super::get_fdt_addr;
use hypervisor::kvm::kvm_bindings::{
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
};
use hypervisor::{arm64_core_reg_id, offset__of};
use std::sync::Arc;
use std::{mem, result};
use vm_memory::Address;
/// Errors thrown while setting aarch64 registers.
#[derive(Debug)]
@@ -67,7 +67,7 @@ pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, cpu_id: u8, boot_ip: u64) ->
let regs0 = offset__of!(user_pt_regs, regs) + kreg_off;
vcpu.set_reg(
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
super::layout::FDT_START.raw_value(),
get_fdt_addr() as u64,
)
.map_err(Error::SetCoreRegister)?;
}

View File

@@ -85,8 +85,8 @@ pub mod aarch64;
#[cfg(target_arch = "aarch64")]
pub use aarch64::{
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
layout::IRQ_BASE, uefi, EntryPoint,
get_host_cpu_phys_bits, get_kernel_start, get_uefi_start, initramfs_load_addr, layout,
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, uefi, EntryPoint,
};
#[cfg(target_arch = "x86_64")]
@@ -158,7 +158,6 @@ impl fmt::Display for DeviceType {
#[cfg(target_arch = "aarch64")]
pub struct MmioDeviceInfo {
pub addr: u64,
pub len: u64,
pub irq: u32,
}
@@ -181,6 +180,6 @@ impl DeviceInfoForFdt for MmioDeviceInfo {
self.irq
}
fn length(&self) -> u64 {
self.len
4096
}
}

View File

@@ -24,9 +24,6 @@ pub const LOW_RAM_START: GuestAddress = GuestAddress(0x0);
// == Fixed addresses within the "Low RAM" range: ==
// Location of EBDA address
pub const EBDA_POINTER: GuestAddress = GuestAddress(0x40e);
// Initial GDT/IDT needed to boot kernel
pub const BOOT_GDT_START: GuestAddress = GuestAddress(0x500);
pub const BOOT_IDT_START: GuestAddress = GuestAddress(0x520);

View File

@@ -186,13 +186,6 @@ pub enum Error {
/// Error checking CPUID compatibility
CpuidCheckCompatibility,
// Error writing EBDA address
EbdaSetup(vm_memory::GuestMemoryError),
/// Error retrieving TDX capabilities through the hypervisor (kvm/mshv) API
#[cfg(feature = "tdx")]
TdxCapabilities(HypervisorError),
}
impl From<Error> for super::Error {
@@ -604,39 +597,9 @@ pub fn generate_common_cpuid(
update_cpuid_sgx(&mut cpuid, sgx_epc_sections)?;
}
#[cfg(feature = "tdx")]
let tdx_capabilities = if tdx_enabled {
let caps = hypervisor
.tdx_capabilities()
.map_err(Error::TdxCapabilities)?;
info!("TDX capabilities {:#?}", caps);
Some(caps)
} else {
None
};
// Update some existing CPUID
for entry in cpuid.as_mut_slice().iter_mut() {
match entry.function {
0xd =>
{
#[cfg(feature = "tdx")]
if let Some(caps) = &tdx_capabilities {
let xcr0_mask: u64 = 0x82ff;
let xss_mask: u64 = !xcr0_mask;
if entry.index == 0 {
entry.eax &= (caps.xfam_fixed0 as u32) & (xcr0_mask as u32);
entry.eax |= (caps.xfam_fixed1 as u32) & (xcr0_mask as u32);
entry.edx &= ((caps.xfam_fixed0 & xcr0_mask) >> 32) as u32;
entry.edx |= ((caps.xfam_fixed1 & xcr0_mask) >> 32) as u32;
} else if entry.index == 1 {
entry.ecx &= (caps.xfam_fixed0 as u32) & (xss_mask as u32);
entry.ecx |= (caps.xfam_fixed1 as u32) & (xss_mask as u32);
entry.edx &= ((caps.xfam_fixed0 & xss_mask) >> 32) as u32;
entry.edx |= ((caps.xfam_fixed1 & xss_mask) >> 32) as u32;
}
}
}
// Set CPU physical bits
0x8000_0008 => {
entry.eax = (entry.eax & 0xffff_ff00) | (phys_bits as u32 & 0xff);
@@ -839,11 +802,6 @@ pub fn configure_system(
rsdp_addr: Option<GuestAddress>,
sgx_epc_region: Option<SgxEpcRegion>,
) -> super::Result<()> {
// Write EBDA address to location where ACPICA expects to find it
guest_mem
.write_obj((layout::EBDA_START.0 >> 4) as u16, layout::EBDA_POINTER)
.map_err(Error::EbdaSetup)?;
let size = smbios::setup_smbios(guest_mem).map_err(Error::SmbiosSetup)?;
// Place the MP table after the SMIOS table aligned to 16 bytes

View File

@@ -324,10 +324,10 @@ impl TdHob {
},
/* TODO:
* QEMU currently fills it in like this:
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED
* EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_ENCRYPTED | EFI_RESOURCE_ATTRIBUTE_TESTED
* which differs from the spec (due to TDVF implementation issue?)
*/
0x7,
0x04000007,
)
}

View File

@@ -2,22 +2,22 @@
name = "block_util"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[features]
default = []
[dependencies]
io-uring = "0.5.2"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
qcow = { path = "../qcow" }
thiserror = "1.0.30"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vhdx = { path = "../vhdx" }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.2.0"
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.9.0"

View File

@@ -209,7 +209,7 @@ impl Request {
let hdr_desc_addr = hdr_desc
.addr()
.translate_gva(access_platform, hdr_desc.len() as usize);
.translate(access_platform, hdr_desc.len() as usize);
let mut req = Request {
request_type: request_type(desc_chain.memory(), hdr_desc_addr)?,
@@ -249,8 +249,7 @@ impl Request {
}
req.data_descriptors.push((
desc.addr()
.translate_gva(access_platform, desc.len() as usize),
desc.addr().translate(access_platform, desc.len() as usize),
desc.len(),
));
desc = desc_chain
@@ -275,7 +274,7 @@ impl Request {
req.status_addr = status_desc
.addr()
.translate_gva(access_platform, status_desc.len() as usize);
.translate(access_platform, status_desc.len() as usize);
Ok(req)
}

View File

@@ -2,17 +2,17 @@
name = "devices"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
edition = "2018"
[dependencies]
acpi_tables = { path = "../acpi_tables" }
anyhow = "1.0.56"
acpi_tables = { path = "../acpi_tables", optional = true }
anyhow = "1.0.55"
arch = { path = "../arch" }
bitflags = "1.3.2"
byteorder = "1.4.3"
epoll = "4.3.1"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vm-device = { path = "../vm-device" }
@@ -22,5 +22,6 @@ vmm-sys-util = "0.9.0"
[features]
default = []
acpi = ["acpi_tables"]
cmos = []
fwdebug = []

View File

@@ -102,6 +102,7 @@ impl BusDevice for AcpiGedDevice {
}
}
#[cfg(feature = "acpi")]
impl Aml for AcpiGedDevice {
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
aml::Device::new(

View File

@@ -76,7 +76,6 @@ impl InterruptController for Gic {
.update(
i as InterruptIndex,
InterruptSourceConfig::LegacyIrq(config),
false,
)
.map_err(Error::EnableInterrupt)?;
}

View File

@@ -367,13 +367,19 @@ impl Ioapic {
};
self.interrupt_source_group
.update(
irq as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
interrupt_mask(entry) == 1,
)
.update(irq as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
.map_err(Error::UpdateInterrupt)?;
if interrupt_mask(entry) == 1 {
self.interrupt_source_group
.mask(irq as InterruptIndex)
.map_err(Error::MaskInterrupt)?;
} else {
self.interrupt_source_group
.unmask(irq as InterruptIndex)
.map_err(Error::UnmaskInterrupt)?;
}
Ok(())
}
}

View File

@@ -7,7 +7,6 @@ use std::cmp::min;
use std::mem;
use std::sync::{Arc, Barrier};
use vm_device::BusDevice;
use vmm_sys_util::eventfd::EventFd;
// https://github.com/rust-lang/libc/issues/1848
#[cfg_attr(target_env = "musl", allow(deprecated))]
@@ -22,14 +21,13 @@ const DATA_LEN: usize = 128;
pub struct Cmos {
index: u8,
data: [u8; DATA_LEN],
reset_evt: EventFd,
}
impl Cmos {
/// Constructs a CMOS/RTC device with initial data.
/// `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.
pub fn new(mem_below_4g: u64, mem_above_4g: u64, reset_evt: EventFd) -> Cmos {
pub fn new(mem_below_4g: u64, mem_above_4g: u64) -> Cmos {
let mut data = [0u8; DATA_LEN];
// Extended memory from 16 MB to 4 GB in units of 64 KB
@@ -46,11 +44,7 @@ impl Cmos {
data[0x5c] = (high_mem >> 8) as u8;
data[0x5d] = (high_mem >> 16) as u8;
Cmos {
index: 0,
data,
reset_evt,
}
Cmos { index: 0, data }
}
}
@@ -62,15 +56,8 @@ impl BusDevice for Cmos {
}
match offset {
INDEX_OFFSET => self.index = data[0],
DATA_OFFSET => {
if self.index == 0x8f && data[0] == 0 {
info!("CMOS reset");
self.reset_evt.write(1).unwrap();
} else {
self.data[(self.index & INDEX_MASK) as usize] = data[0]
}
}
INDEX_OFFSET => self.index = data[0] & INDEX_MASK,
DATA_OFFSET => self.data[self.index as usize] = data[0],
o => warn!("bad write offset on CMOS device: {}", o),
};
None

View File

@@ -356,7 +356,6 @@ mod tests {
&self,
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}

View File

@@ -5,6 +5,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
#[cfg(feature = "cmos")]
mod cmos;
#[cfg(feature = "fwdebug")]
mod fwdebug;
@@ -17,6 +18,7 @@ mod serial;
#[cfg(target_arch = "aarch64")]
mod uart_pl011;
#[cfg(feature = "cmos")]
pub use self::cmos::Cmos;
#[cfg(feature = "fwdebug")]
pub use self::fwdebug::FwDebugDevice;

View File

@@ -430,7 +430,6 @@ mod tests {
&self,
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}

View File

@@ -339,7 +339,6 @@ mod tests {
&self,
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}

View File

@@ -34,7 +34,6 @@ const UARTRIS: u64 = 15;
const UARTMIS: u64 = 16;
const UARTICR: u64 = 17;
const UARTDMACR: u64 = 18;
const UARTDEBUG: u64 = 0x3c0;
const PL011_INT_TX: u32 = 0x20;
const PL011_INT_RX: u32 = 0x10;
@@ -78,7 +77,6 @@ pub struct Pl011 {
rsr: u32,
cr: u32,
dmacr: u32,
debug: u32,
int_enabled: u32,
int_level: u32,
read_fifo: VecDeque<u8>,
@@ -90,7 +88,6 @@ pub struct Pl011 {
read_trigger: u32,
irq: Arc<dyn InterruptSourceGroup>,
out: Option<Box<dyn io::Write + Send>>,
timestamp: std::time::Instant,
}
#[derive(Versionize)]
@@ -100,7 +97,6 @@ pub struct Pl011State {
rsr: u32,
cr: u32,
dmacr: u32,
debug: u32,
int_enabled: u32,
int_level: u32,
read_fifo: Vec<u8>,
@@ -128,7 +124,6 @@ impl Pl011 {
rsr: 0u32,
cr: 0x300u32,
dmacr: 0u32,
debug: 0u32,
int_enabled: 0u32,
int_level: 0u32,
read_fifo: VecDeque::new(),
@@ -140,7 +135,6 @@ impl Pl011 {
read_trigger: 1u32,
irq,
out,
timestamp: std::time::Instant::now(),
}
}
@@ -155,7 +149,6 @@ impl Pl011 {
rsr: self.rsr,
cr: self.cr,
dmacr: self.dmacr,
debug: self.debug,
int_enabled: self.int_enabled,
int_level: self.int_level,
read_fifo: self.read_fifo.clone().into(),
@@ -174,7 +167,6 @@ impl Pl011 {
self.rsr = state.rsr;
self.cr = state.cr;
self.dmacr = state.dmacr;
self.debug = state.debug;
self.int_enabled = state.int_enabled;
self.int_level = state.int_level;
self.read_fifo = state.read_fifo.clone().into();
@@ -288,50 +280,13 @@ impl Pl011 {
return Err(Error::DmaNotImplemented);
}
}
UARTDEBUG => {
self.debug = val;
self.handle_debug();
}
off => {
debug!("PL011: Bad write offset, offset: {}", off);
return Err(Error::BadWriteOffset(off));
}
}
Ok(())
}
fn handle_debug(&self) {
let elapsed = self.timestamp.elapsed();
match self.debug {
0x00..=0x1f => info!(
"[Debug I/O port: Firmware code: 0x{:x}] {}.{:>06} seconds",
self.debug,
elapsed.as_secs(),
elapsed.as_micros()
),
0x20..=0x3f => info!(
"[Debug I/O port: Bootloader code: 0x{:x}] {}.{:>06} seconds",
self.debug,
elapsed.as_secs(),
elapsed.as_micros()
),
0x40..=0x5f => info!(
"[Debug I/O port: Kernel code: 0x{:x}] {}.{:>06} seconds",
self.debug,
elapsed.as_secs(),
elapsed.as_micros()
),
0x60..=0x7f => info!(
"[Debug I/O port: Userspace code: 0x{:x}] {}.{:>06} seconds",
self.debug,
elapsed.as_secs(),
elapsed.as_micros()
),
_ => {}
}
}
fn trigger_interrupt(&mut self) -> result::Result<(), io::Error> {
self.irq.trigger(0)
}
@@ -372,7 +327,6 @@ impl BusDevice for Pl011 {
UARTRIS => self.int_level,
UARTMIS => (self.int_level & self.int_enabled),
UARTDMACR => self.dmacr,
UARTDEBUG => self.debug,
_ => {
read_ok = false;
0
@@ -450,7 +404,6 @@ mod tests {
&self,
_index: InterruptIndex,
_config: InterruptSourceConfig,
_masked: bool,
) -> result::Result<(), std::io::Error> {
Ok(())
}

View File

@@ -12,6 +12,7 @@ extern crate bitflags;
#[macro_use]
extern crate log;
#[cfg(feature = "acpi")]
pub mod acpi;
#[cfg(target_arch = "aarch64")]
pub mod gic;
@@ -20,6 +21,7 @@ pub mod interrupt_controller;
pub mod ioapic;
pub mod legacy;
#[cfg(feature = "acpi")]
pub use self::acpi::{AcpiGedDevice, AcpiPmTimerDevice, AcpiShutdownDevice};
bitflags! {

View File

@@ -88,8 +88,6 @@ Reboot the VM | `/vm.reboot` | N/A
Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted
Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted
Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused
Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig`| N/A | The VM is paused
Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted
Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted
Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted
@@ -100,7 +98,6 @@ Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig`
Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted
Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted
Add userspace PCI device to the VM | `/vm.add-user-device`| `/schemas/VmAddUserDevice`| `/schemas/PciDeviceInfo` | The VM is booted
Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted
Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted
Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted
Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted

View File

@@ -1,76 +0,0 @@
# Balloon
Cloud Hypervisor implements a balloon device based on the VIRTIO specification.
Its main purpose is to provide the host a way to reclaim memory by controlling
the amount of memory visible to the guest. But it also provides some interesting
features related to guest memory management.
## Parameters
`BalloonConfig` (known as `--balloon` from the CLI perspective) contains the
list of parameters available for the balloon device.
```rust
struct BalloonConfig {
pub size: u64,
pub deflate_on_oom: bool,
pub free_page_reporting: bool,
}
```
```
--balloon <balloon> Balloon parameters "size=<balloon_size>,deflate_on_oom=on|off,free_page_reporting=on|off"
```
### `size`
Size of the balloon device. It is subtracted from the VM's total size. For
instance, if creating a VM with 4GiB of RAM, along with a balloon of 1GiB, the
guest will be able to use 3GiB of accessible memory. The guest sees all the RAM
and unless it is balloon enlightened is entitled to all of it.
This parameter is mandatory.
Value is an unsigned integer of 64 bits corresponding to the balloon size in
bytes.
_Example_
```
--balloon size=1G
```
### `deflate_on_oom`
Allow the guest to deflate the balloon if running Out Of Memory (OOM). Assuming
the balloon size is greater than 0, this means the guest is allowed to reduce
the balloon size all the way down to 0 if this can help recover from the OOM
event.
This parameter is optional.
Value is a boolean set to `off` by default.
_Example_
```
--ballloon size=2G,deflate_on_oom=on
```
### `free_page_reporting`
Allow the guest to report lists of free pages. This feature doesn't require the
balloon to be of any specific size as it doesn't impact the balloon size. The
guest can let the VMM know about pages that are free after they have been used.
Based on this information, the VMM can advise the host that it doesn't need
these pages anymore.
This parameter is optional.
Value is a boolean set to `off` by default.
_Example_
```
--ballloon size=0,free_page_reporting=on
```

View File

@@ -17,12 +17,11 @@ struct CpusConfig {
kvm_hyperv: bool,
max_phys_bits: u8,
affinity: Option<Vec<CpuAffinity>>,
features: CpuFeatures,
}
```
```
--cpus 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 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>
```
### `boot`
@@ -188,24 +187,3 @@ _Example_
In this example, assuming the host has 4 CPUs, vCPU 0 will run exclusively on
host CPUs 2 and 3, while vCPU 1 will run exclusively on host CPUs 0 and 1.
Because nothing is defined for vCPU 2, it can run on any of the 4 host CPUs.
### `features`
Set of CPU features to enable.
This option allows the user to enable a set of CPU features that are disabled
by default otherwise.
The currently available feature set is: `amx`.
The `amx` feature will enable the x86 extension adding hardware units for
matrix operations (int and float dot products). The goal of the extension is to
provide performance enhancements for these common operations.
_Example_
```
--cpus features=amx
```
In this example the amx CPU feature will be enabled for the VMM.

View File

@@ -1,18 +1,14 @@
# How to use virtio-fs
In the context of virtualization, it is always convenient to be able to share a
directory from the host with the guest.
In the context of virtualization, it is always convenient to be able to share a directory from the host with the guest.
__virtio-fs__, also known as __vhost-user-fs__ is a virtual device defined by
the VIRTIO specification which allows any VMM to perform filesystem sharing.
__virtio-fs__, also known as __vhost-user-fs__ is a virtual device defined by the VIRTIO specification which allows any VMM to perform filesystem sharing.
## Pre-requisites
### The daemon
This virtual device relies on the _vhost-user_ protocol, which assumes the
backend (device emulation) is handled by a dedicated process running on the
host. This daemon is called __virtiofsd__ and needs to be present on the host.
This virtual device relies on the _vhost-user_ protocol, which assumes the backend (device emulation) is handled by a dedicated process running on the host. This daemon is called __virtiofsd__ and needs to be present on the host.
_Build virtiofsd_
```bash
@@ -35,35 +31,25 @@ _Run virtiofsd_
--cache=never
```
The `cache=never` option is the default when using `virtiofsd` with
Cloud Hypervisor. This prevents from using the host page cache, reducing the
overall footprint on host memory. This increases the maximum density of virtual
machines that can be launched on a single host.
The `cache=never` option should be the default when using `virtiofsd` with the __cloud-hypervisor__ VMM. This prevents from using the guest page cache, which reduces the memory footprint of the guest. When running multiple virtual machines on the same host, this will let the host deal with page cache, which will increase the density of virtual machines which can be launched.
The `cache=always` option will allow the host page cache to be used, which can
result in better performance for the guest's workload at the cost of increasing
the footprint on host memory.
The `cache=always` option will allow for the guest page cache to be used, which will increase the memory footprint of the guest. This option should be used only for specific use cases where a single VM is going to be running on a host.
### Kernel support
Modern Linux kernels (at least v5.10) have support for virtio-fs. Use of older
kernels, with additional patches, are not supported.
Modern Linux kernels starting (at least v5.10) have support for virtio-fs. Use
of older kernels, with additional patches, are not supported.
## How to share directories with cloud-hypervisor
### Start the VM
Once the daemon is running, the option `--fs` from __cloud-hypervisor__ needs to be used.
Once the daemon is running, the option `--fs` from Cloud Hypervisor needs
to be used.
Direct kernel boot is the preferred option, but we can boot from an EFI cloud image if it contains a recent enough kernel.
Both direct kernel boot and EFI firmware can be used to boot a VM with
virtio-fs, given that the cloud image contains a recent enough kernel.
Because _vhost-user_ expects a dedicated process (__virtiofsd__ in this case) to be able to access the guest RAM to communicate through the _virtqueues_ with the driver running in the guest, `--memory` option needs to be slightly modified. It must specify `shared=on` to share the memory pages so that an external process can access them.
Correct functioning of `--fs` requires `--memory shared=on` to facilitate
interprocess memory sharing.
Assuming you have `focal-server-cloudimg-amd64.raw` and `vmlinux` on your
system, here is the Cloud Hypervisor command you need to run:
Assuming you have `focal-server-cloudimg-amd64.raw` and `vmlinux` on your system, here is the __cloud-hypervisor__ command you need to run:
```bash
./cloud-hypervisor \
--cpus boot=1 \
@@ -74,20 +60,26 @@ system, here is the Cloud Hypervisor command you need to run:
--fs tag=myfs,socket=/tmp/virtiofs,num_queues=1,queue_size=512
```
### Mount the shared directory
The last step is to mount the shared directory inside the guest, using the
`virtiofs` filesystem type.
By default, DAX is enabled with a cache window of 8GiB. You can specify a custom size (let's say 4GiB for this example) for the cache by explicitly setting DAX and the cache size:
```bash
mkdir mount_dir
mount -t virtiofs myfs mount_dir/
--fs tag=myfs,socket=/tmp/virtiofs,num_queues=1,queue_size=512,dax=on,cache_size=4G
```
The `tag` needs to be consistent with what has been provided through the
Cloud Hypervisor command line, which happens to be `myfs` in this example.
In case you don't want to use a shared window of cache to pass the shared files content, this means you will have to explicitly disable DAX with `dax=off`. Note that in this case, the `cache_size` parameter will be ignored.
## DAX feature
```bash
--fs tag=myfs,socket=/tmp/virtiofs,num_queues=1,queue_size=512,dax=off
Given the DAX feature is not stable yet from a daemon standpoint, it is not
available in Cloud Hypervisor.
```
### Mount the shared directory
The last step is to mount the shared directory inside the guest, using the `virtiofs` filesystem type.
```bash
mkdir mount_dir
mount -t virtiofs -o dax myfs mount_dir/
```
The `tag` needs to be consistent with what has been provided through the __cloud-hypervisor__ command line, which happens to be `myfs` in this example.
The `-o dax` option must be removed in case the shared cache region is not enabled from the VMM.

View File

@@ -55,9 +55,9 @@ cargo build --features tdx
```
And run a TDX VM by providing the firmware previously built, along with the
guest image containing the TDX enlightened kernel. The latest image
`td-guest-rhel8.5.raw` contains `console=hvc0` on the kernel boot parameters,
meaning it will be printing guest kernel logs to the `virtio-console` device.
guest image containing the TDX enlightened kernel. Assuming the guest kernel
command line contains `console=hvc0` (printing to the `virtio-console` device),
run Cloud Hypervisor as follows:
```bash
./cloud-hypervisor \
@@ -67,8 +67,8 @@ meaning it will be printing guest kernel logs to the `virtio-console` device.
--disk path=tdx_guest_img
```
And here is the alternative command when looking for debug logs from the
firmware:
And here is the alternative command when looking for debug logs (assuming the
guest kernel command line contains `console=ttyS0`):
```bash
./cloud-hypervisor \
@@ -76,8 +76,8 @@ firmware:
--cpus boot=1 \
--memory size=1G \
--disk path=tdx_guest_img \
--serial file=/tmp/ch_serial \
--console tty
--serial tty \
--console off
```
### TDShim
@@ -97,14 +97,8 @@ option as well.
./cloud-hypervisor \
--tdx firmware=tdshim \
--kernel bzImage \
--cmdline "root=/dev/vda3 console=hvc0 rw"
--cmdline "root=/dev/vda1 console=hvc0 rw tdx_allow_acpi=MCFG"
--cpus boot=1 \
--memory size=1G \
--disk path=tdx_guest_img
```
### Guest kernel disables serial ports
The latest guest kernel that can be found in the latest image
`td-guest-rhel8.5.raw` disabled the support for serial ports. This means adding
`console=ttyS0` will have no effect and will not print any log from the guest.
```

View File

@@ -24,8 +24,8 @@ bucket is unbounded in speed which allows for bursts bound in size by
the amount of tokens available. Once the token bucket is empty,
consumption speed is bound by the "refill-rate". Similarly, Cloud
Hypervisor provides another three options for limiting I/O operations,
i.e., `ops_size` (I/O operations), `ops_one_time_burst` (I/O operations),
and `ops_refill_time` (ms).
i.e., `ops_size` (I/O operations), `bw_one_time_burst` (I/O operations),
and `bw_refill_time` (ms).
One caveat in the I/O throttling is that every-time the bucket gets
empty, it will stop I/O operations for a fixed amount of time

View File

@@ -231,38 +231,3 @@ Last thing is to start the L2 guest with the huge pages memory backend.
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
--device path=/sys/bus/pci/devices/0000:00:04.0
```
### Dedicated IOMMU PCI segments
To facilitate hotplug of devices that require being behind an IOMMU it is
possible to mark entire PCI segments as behind the IOMMU.
This is accomplished through `--platform
num_pci_segments=<number_of_segments>,iommu_segments=<range of segments>` or
via the equivalents in `PlatformConfig` for the API.
e.g.
```bash
./cloud-hypervisor \
--api-socket=/tmp/api \
--cpus boot=1 \
--memory size=4G,hugepages=on \
--disk path=focal-server-cloudimg-amd64.raw \
--kernel custom-vmlinux \
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
--platform num_pci_segments=2,iommu_segments=1
```
This adds a second PCI segment to the platform behind the IOMMU. A VFIO device
requiring the IOMMU then may be hotplugged:
e.g.
```bash
./ch-remote --api-socket=/tmp/api add-device path=/sys/bus/pci/devices/0000:00:04.0,iommu=on,pci_segment=1
```
Devices that cannot be placed behind an IOMMU (e.g. lacking an `iommu=` option)
cannot be placed on the IOMMU segments.

View File

@@ -1,29 +0,0 @@
# Performance Metrics
Cloud Hypervisor provides a [performance metrics](https://github.com/cloud-hypervisor/cloud-hypervisor/tree/main/performance-metrics)
binary for users to generate metrics data from their own
environment. This document describes how to generate metrics data
quickly by using Cloud Hypervisor's development script,
e.g. `dev_cli.sh`. The only prerequisite is [Docker installation](https://docs.docker.com/engine/install/).
Please note that upon its first invocation, this script will pull a
fairly large container image.
To generate metrics data for all available performance tests (including
boot time, block I/O throughput, and network throughput & latency) and
output the result into a json file:
```
$ ./scripts/dev_cli.sh tests --metrics -- -- --report-file /tmp/metrics.json
```
To get a list of available performance tests:
```
$ ./scripts/dev_cli.sh tests --metrics -- -- --list-tests
```
To generate metrics data for selected performance tests, e.g. boot time only:
```
$ ./scripts/dev_cli.sh tests --metrics -- -- --report-file /tmp/metrics.json --test-filter boot_time
```

View File

@@ -1,154 +0,0 @@
# Virtio Data Path Acceleration
vDPA aims at achieving bare-metal performance for devices passed into a virtual
machine. It is an alternative to VFIO, as it provides a simpler solution for
achieving migration.
It is a kernel framework introduced recently to handle devices complying with
the VIRTIO specification on their data-path, while the control path is vendor
specific. In practice, virtqueues are accessed directly through DMA mechanism
between the hardware and the guest. The control path is accessed through the
vDPA framework, being exposed through the vhost interface as a vhost-vdpa
device.
Because DMA accesses between device and guest are going through virtqueues,
migration can be achieved without requiring device's driver to implement any
specific migration support. In case of VFIO, each vendor is expected to provide
an implementation of the VFIO migration framework, complicating things as it
must be done for each and every device's driver.
The official [website](https://vdpa-dev.gitlab.io/) contains some extensive
documentation on the topic.
## Usage
`VdpaConfig` (known as `--vdpa` from the CLI perspective) contains the list of
parameters available for the vDPA device.
```rust
struct VdpaConfig {
path: PathBuf,
num_queues: usize,
id: Option<String>,
pci_segment: u16,
}
```
```
--vdpa <vdpa> vDPA device "path=<device_path>,num_queues=<number_of_queues>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>"
```
### `path`
Path of the vDPA device. Usually `/dev/vhost-vdpa-X`.
This parameter is mandatory.
Value is a string.
_Example_
```
--vdpa path=/dev/vhost-vdpa-0
```
### `num_queues`
Number of virtqueues supported by the vDPA device.
This parameter is optional.
Value is an unsigned integer set to `1` by default.
_Example_
```
--vdpa path=/dev/vhost-vdpa-0,num_queues=2
```
### `id`
Identifier of the vDPA device.
This parameter is optional. If provided, it must be unique across the entire
virtual machine.
Value is a string.
_Example_
```
--vdpa path=/dev/vhost-vdpa-0,id=vdpa0
```
### `pci_segment`
PCI segment number to which the vDPA device should be attached to.
This parameter is optional.
Value is an unsigned integer of 16 bits set to `0` by default.
_Example_
```
--vdpa path=/dev/vhost-vdpa-0,pci_segment=1
```
## Example with vDPA block simulator
The vDPA framework provides a simulator with both `virtio-block` and
`virtio-net` implementations. This is very useful for testing vDPA when we
don't have access to the specific hardware.
Given the host kernel has the appropriate modules available, let's load them
all:
```
sudo modprobe vdpa
sudo modprobe vhost_vdpa
sudo modprobe vdpa_sim
sudo modprobe vdpa_sim_blk
```
Given you have the `iproute2/vdpa` tool installed, let's now create the
`virtio-block` vDPA device:
```sh
sudo vdpa dev add name vdpa-blk1 mgmtdev vdpasim_blk
sudo chown $USER:$USER /dev/vhost-vdpa-0
sudo chmod 660 /dev/vhost-vdpa-0
```
Increase the maximum locked memory to ensure setting up IOMMU mappings will
succeed:
```sh
ulimit -l unlimited
```
Start Cloud Hypervisor:
```sh
cloud-hypervisor \
--cpus boot=1 \
--memory size=1G,hugepages=on \
--disk path=focal-server-cloudimg-amd64.raw \
--kernel vmlinux \
--cmdline "root=/dev/vda1 console=hvc0" \
--vdpa path=/dev/vhost-vdpa-0,num_queues=1
```
The `virtio-block` device backed by the vDPA simulator can be found as
`/dev/vdb` in the guest:
```
cloud@cloud:~$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
nullb0 252:0 0 250G 0 disk
vda 254:0 0 2.2G 0 disk
├─vda1 254:1 0 2.1G 0 part /
├─vda14 254:14 0 4M 0 part
└─vda15 254:15 0 106M 0 part /boot/efi
vdb 254:16 0 128M 0 disk
```

View File

@@ -2,10 +2,10 @@
name = "event_monitor"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
libc = "0.2.123"
libc = "0.2.119"
serde = { version = "1.0.136", features = ["rc"] }
serde_derive = "1.0.136"
serde_json = "1.0.79"

68
fuzz/Cargo.lock generated
View File

@@ -11,9 +11,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.56"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
[[package]]
name = "api_client"
@@ -128,9 +128,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "3.1.8"
version = "3.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
dependencies = [
"atty",
"bitflags",
@@ -145,7 +145,7 @@ dependencies = [
[[package]]
name = "cloud-hypervisor"
version = "22.0.0"
version = "21.0.0"
dependencies = [
"anyhow",
"api_client",
@@ -185,9 +185,9 @@ dependencies = [
[[package]]
name = "crc32c"
version = "0.6.3"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dfea2db42e9927a3845fb268a10a72faed6d416065f77873f05e411457c363e"
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
dependencies = [
"rustc_version",
]
@@ -270,9 +270,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.6"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
@@ -325,9 +325,9 @@ dependencies = [
[[package]]
name = "indexmap"
version = "1.8.1"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
@@ -377,15 +377,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.123"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb691a747a7ab48abc15c5b42066eaafde10dc427e3b6ee2a1cf43db04c763bd"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "libfuzzer-sys"
version = "0.4.3"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "336244aaeab6a12df46480dc585802aa743a72d66b11937844c61bbca84c991d"
checksum = "36a9a84a6e8b55dfefb04235e55edb2b9a2a18488fcae777a6bdaa6f06f1deb3"
dependencies = [
"arbitrary",
"cc",
@@ -403,9 +403,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.16"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
@@ -469,9 +469,9 @@ dependencies = [
[[package]]
name = "once_cell"
version = "1.10.0"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
[[package]]
name = "option_parser"
@@ -488,9 +488,9 @@ dependencies = [
[[package]]
name = "paste"
version = "1.0.7"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c520e05135d6e763148b6426a837e239041653ba7becd2e538c076c738025fc"
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
[[package]]
name = "pci"
@@ -518,9 +518,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.37"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
@@ -538,9 +538,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.18"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
@@ -591,9 +591,9 @@ dependencies = [
[[package]]
name = "semver"
version = "1.0.7"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
[[package]]
name = "serde"
@@ -656,9 +656,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.91"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
@@ -812,9 +812,9 @@ dependencies = [
[[package]]
name = "vhost"
version = "0.4.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53567fd9ab820e4f3cc156f24146882fee3c365194c3e1dea74723265f27fc88"
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
dependencies = [
"bitflags",
"libc",
@@ -849,7 +849,6 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"thiserror",
"versionize",
"versionize_derive",
"vhost",
@@ -865,9 +864,8 @@ dependencies = [
[[package]]
name = "virtio-queue"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3785325315e6496fa88673842ee6cd198b9658e88e8b0e1ad48a5dc818b221dc"
version = "0.1.0"
source = "git+https://github.com/rust-vmm/vm-virtio?branch=main#bbb22d43558a76cc7cc9c262c4be870a9e682a86"
dependencies = [
"log",
"vm-memory",

View File

@@ -3,20 +3,20 @@ name = "cloud-hypervisor-fuzz"
version = "0.0.0"
authors = ["Automatically generated"]
publish = false
edition = "2021"
edition = "2018"
[package.metadata]
cargo-fuzz = true
[dependencies]
block_util = { path = "../block_util" }
libc = "0.2.123"
libfuzzer-sys = "0.4.3"
libc = "0.2.119"
libfuzzer-sys = "0.4.2"
qcow = { path = "../qcow" }
seccompiler = "0.2.0"
vhdx = { path = "../vhdx" }
virtio-devices = { path = "../virtio-devices" }
virtio-queue = "0.2.0"
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
vmm-sys-util = "0.9.0"
vm-virtio = { path = "../vm-virtio" }
vm-memory = "0.7.0"

View File

@@ -2,7 +2,7 @@
name = "hypervisor"
version = "0.1.0"
authors = ["Microsoft Authors"]
edition = "2021"
edition = "2018"
license = "Apache-2.0 OR BSD-3-Clause"
[features]
@@ -11,11 +11,11 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
tdx = []
[dependencies]
anyhow = "1.0.56"
anyhow = "1.0.55"
epoll = "4.3.1"
thiserror = "1.0.30"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
kvm-ioctls = { version = "0.11.0", optional = true }
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.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 }

View File

@@ -12,8 +12,6 @@ use crate::vm::Vm;
use crate::x86_64::CpuId;
#[cfg(target_arch = "x86_64")]
use crate::x86_64::MsrList;
#[cfg(feature = "tdx")]
use crate::TdxCapabilities;
use std::sync::Arc;
use thiserror::Error;
@@ -61,11 +59,6 @@ pub enum HypervisorError {
///
#[error("Checking extensions:{0}")]
CheckExtensions(#[source] anyhow::Error),
///
/// Failed to retrieve TDX capabilities
///
#[error("Failed to retrieve TDX capabilities:{0}")]
TdxCapabilities(#[source] anyhow::Error),
}
///
@@ -112,9 +105,4 @@ pub trait Hypervisor: Send + Sync {
/// Retrieve AArch64 host maximum IPA size supported by KVM.
///
fn get_host_ipa_limit(&self) -> i32;
///
/// Retrieve TDX capabilities
///
#[cfg(feature = "tdx")]
fn tdx_capabilities(&self) -> Result<TdxCapabilities>;
}

View File

@@ -107,6 +107,7 @@ ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
#[cfg(feature = "tdx")]
#[repr(u32)]
enum TdxCommand {
#[allow(dead_code)]
Capabilities = 0,
InitVm,
InitVcpu,
@@ -126,34 +127,6 @@ pub enum TdxExitStatus {
InvalidOperand,
}
#[cfg(feature = "tdx")]
const TDX_MAX_NR_CPUID_CONFIGS: usize = 6;
#[cfg(feature = "tdx")]
#[repr(C)]
#[derive(Debug, Default)]
pub struct TdxCpuidConfig {
pub leaf: u32,
pub sub_leaf: u32,
pub eax: u32,
pub ebx: u32,
pub ecx: u32,
pub edx: u32,
}
#[cfg(feature = "tdx")]
#[repr(C)]
#[derive(Debug, Default)]
pub struct TdxCapabilities {
pub attrs_fixed0: u64,
pub attrs_fixed1: u64,
pub xfam_fixed0: u64,
pub xfam_fixed1: u64,
pub nr_cpuid_configs: u32,
pub padding: u32,
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
}
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
pub struct KvmVmState {}
@@ -552,7 +525,7 @@ impl vm::Vm for KvmVm {
let data = TdxInitVm {
max_vcpus,
tsc_khz: 0,
attributes: 0,
attributes: 1, // TDX1_TD_ATTRIBUTE_DEBUG,
cpuid: cpuid.as_fam_struct_ptr() as u64,
mrconfigid: [0; 6],
mrowner: [0; 6],
@@ -789,27 +762,6 @@ impl hypervisor::Hypervisor for KvmHypervisor {
fn get_host_ipa_limit(&self) -> i32 {
self.kvm.get_host_ipa_limit()
}
///
/// Retrieve TDX capabilities
///
#[cfg(feature = "tdx")]
fn tdx_capabilities(&self) -> hypervisor::Result<TdxCapabilities> {
let data = TdxCapabilities {
nr_cpuid_configs: TDX_MAX_NR_CPUID_CONFIGS as u32,
..Default::default()
};
tdx_command(
&self.kvm.as_raw_fd(),
TdxCommand::Capabilities,
0,
&data as *const _ as u64,
)
.map_err(|e| hypervisor::HypervisorError::TdxCapabilities(e.into()))?;
Ok(data)
}
}
/// Vcpu struct for KVM
pub struct KvmVcpu {

View File

@@ -51,8 +51,6 @@ mod device;
pub use crate::hypervisor::{Hypervisor, HypervisorError};
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
pub use device::{Device, HypervisorDeviceError};
#[cfg(feature = "tdx")]
pub use kvm::TdxCapabilities;
#[cfg(feature = "kvm")]
pub use kvm::*;
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]

View File

@@ -134,7 +134,7 @@ impl hypervisor::Hypervisor for MshvHypervisor {
}
#[cfg(target_arch = "x86_64")]
///
/// Retrieve the list of MSRs supported by MSHV.
/// Retrieve the list of MSRs supported by KVM.
///
fn get_msr_list(&self) -> hypervisor::Result<MsrList> {
self.mshv

View File

@@ -2,7 +2,7 @@
name = "net_gen"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
edition = "2018"
[dependencies]
vmm-sys-util = "0.9.0"

View File

@@ -2,20 +2,20 @@
name = "net_util"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
edition = "2018"
[dependencies]
epoll = "4.3.1"
getrandom = "0.2"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
net_gen = { path = "../net_gen" }
rate_limiter = { path = "../rate_limiter" }
serde = "1.0.136"
versionize = "0.1.6"
versionize_derive = "0.1.4"
virtio-bindings = "0.1.0"
virtio-queue = "0.2.0"
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
vm-virtio = { path = "../vm-virtio" }
vmm-sys-util = "0.9.0"

View File

@@ -60,103 +60,97 @@ impl CtrlQueue {
&mut self,
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
access_platform: Option<&Arc<dyn AccessPlatform>>,
) -> Result<()> {
) -> Result<bool> {
let mut used_desc_heads = Vec::new();
loop {
for mut desc_chain in queue.iter().map_err(Error::QueueIterator)? {
let ctrl_desc = desc_chain.next().ok_or(Error::NoControlHeaderDescriptor)?;
for mut desc_chain in queue.iter().map_err(Error::QueueIterator)? {
let ctrl_desc = desc_chain.next().ok_or(Error::NoControlHeaderDescriptor)?;
let ctrl_hdr: ControlHeader = desc_chain
.memory()
.read_obj(
ctrl_desc
.addr()
.translate_gva(access_platform, ctrl_desc.len() as usize),
)
.map_err(Error::GuestMemory)?;
let data_desc = desc_chain.next().ok_or(Error::NoDataDescriptor)?;
let ctrl_hdr: ControlHeader = desc_chain
.memory()
.read_obj(
ctrl_desc
.addr()
.translate(access_platform, ctrl_desc.len() as usize),
)
.map_err(Error::GuestMemory)?;
let data_desc = desc_chain.next().ok_or(Error::NoDataDescriptor)?;
let data_desc_addr = data_desc
.addr()
.translate_gva(access_platform, data_desc.len() as usize);
let data_desc_addr = data_desc
.addr()
.translate(access_platform, data_desc.len() as usize);
let status_desc = desc_chain.next().ok_or(Error::NoStatusDescriptor)?;
let status_desc = desc_chain.next().ok_or(Error::NoStatusDescriptor)?;
let ok = match u32::from(ctrl_hdr.class) {
VIRTIO_NET_CTRL_MQ => {
let queue_pairs = desc_chain
.memory()
.read_obj::<u16>(data_desc_addr)
.map_err(Error::GuestMemory)?;
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
warn!("Unsupported command: {}", ctrl_hdr.cmd);
false
} else if (queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN as u16)
|| (queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as u16)
{
warn!("Number of MQ pairs out of range: {}", queue_pairs);
false
} else {
info!("Number of MQ pairs requested: {}", queue_pairs);
true
}
}
VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
let features = desc_chain
.memory()
.read_obj::<u64>(data_desc_addr)
.map_err(Error::GuestMemory)?;
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET {
warn!("Unsupported command: {}", ctrl_hdr.cmd);
false
} else {
let mut ok = true;
for tap in self.taps.iter_mut() {
info!("Reprogramming tap offload with features: {}", features);
tap.set_offload(virtio_features_to_tap_offload(features))
.map_err(|e| {
error!("Error programming tap offload: {:?}", e);
ok = false
})
.ok();
}
ok
}
}
_ => {
warn!("Unsupported command {:?}", ctrl_hdr);
let ok = match u32::from(ctrl_hdr.class) {
VIRTIO_NET_CTRL_MQ => {
let queue_pairs = desc_chain
.memory()
.read_obj::<u16>(data_desc_addr)
.map_err(Error::GuestMemory)?;
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
warn!("Unsupported command: {}", ctrl_hdr.cmd);
false
} else if (queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN as u16)
|| (queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX as u16)
{
warn!("Number of MQ pairs out of range: {}", queue_pairs);
false
} else {
info!("Number of MQ pairs requested: {}", queue_pairs);
true
}
};
}
VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
let features = desc_chain
.memory()
.read_obj::<u64>(data_desc_addr)
.map_err(Error::GuestMemory)?;
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET {
warn!("Unsupported command: {}", ctrl_hdr.cmd);
false
} else {
let mut ok = true;
for tap in self.taps.iter_mut() {
info!("Reprogramming tap offload with features: {}", features);
tap.set_offload(virtio_features_to_tap_offload(features))
.map_err(|e| {
error!("Error programming tap offload: {:?}", e);
ok = false
})
.ok();
}
ok
}
}
_ => {
warn!("Unsupported command {:?}", ctrl_hdr);
false
}
};
desc_chain
.memory()
.write_obj(
if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8,
status_desc
.addr()
.translate_gva(access_platform, status_desc.len() as usize),
)
.map_err(Error::GuestMemory)?;
let len = ctrl_desc.len() + data_desc.len() + status_desc.len();
used_desc_heads.push((desc_chain.head_index(), len));
}
for (desc_index, len) in used_desc_heads.iter() {
queue
.add_used(*desc_index, *len)
.map_err(Error::QueueAddUsed)?;
}
if !queue
.enable_notification()
.map_err(Error::QueueEnableNotification)?
{
break;
}
desc_chain
.memory()
.write_obj(
if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8,
status_desc
.addr()
.translate(access_platform, status_desc.len() as usize),
)
.map_err(Error::GuestMemory)?;
let len = ctrl_desc.len() + data_desc.len() + status_desc.len();
used_desc_heads.push((desc_chain.head_index(), len));
}
Ok(())
for (desc_index, len) in used_desc_heads.iter() {
queue
.add_used(*desc_index, *len)
.map_err(Error::QueueAddUsed)?;
queue
.enable_notification()
.map_err(Error::QueueEnableNotification)?;
}
Ok(!used_desc_heads.is_empty())
}
}

View File

@@ -60,9 +60,7 @@ impl TxVirtio {
let mut iovecs = Vec::new();
while let Some(desc) = next_desc {
let desc_addr = desc
.addr()
.translate_gva(access_platform, desc.len() as usize);
let desc_addr = desc.addr().translate(access_platform, desc.len() as usize);
if !desc.is_write_only() && desc.len() > 0 {
let buf = desc_chain
.memory()
@@ -132,12 +130,9 @@ impl TxVirtio {
queue
.add_used(used_desc_head.0, used_desc_head.1)
.map_err(NetQueuePairError::QueueAddUsed)?;
if !queue
queue
.enable_notification()
.map_err(NetQueuePairError::QueueEnableNotification)?
{
break;
}
.map_err(NetQueuePairError::QueueEnableNotification)?;
}
Ok(retry_write)
@@ -194,8 +189,7 @@ impl RxVirtio {
let num_buffers_addr = desc_chain
.memory()
.checked_offset(
desc.addr()
.translate_gva(access_platform, desc.len() as usize),
desc.addr().translate(access_platform, desc.len() as usize),
10,
)
.unwrap();
@@ -203,9 +197,7 @@ impl RxVirtio {
let mut iovecs = Vec::new();
while let Some(desc) = next_desc {
let desc_addr = desc
.addr()
.translate_gva(access_platform, desc.len() as usize);
let desc_addr = desc.addr().translate(access_platform, desc.len() as usize);
if desc.is_write_only() && desc.len() > 0 {
let buf = desc_chain
.memory()
@@ -283,12 +275,9 @@ impl RxVirtio {
queue
.add_used(used_desc_head.0, used_desc_head.1)
.map_err(NetQueuePairError::QueueAddUsed)?;
if !queue
queue
.enable_notification()
.map_err(NetQueuePairError::QueueEnableNotification)?
{
break;
}
.map_err(NetQueuePairError::QueueEnableNotification)?;
}
Ok(exhausted_descs)

View File

@@ -2,4 +2,4 @@
name = "option_parser"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"

View File

@@ -313,7 +313,6 @@ impl<S: FromStr, T: TupleValue> FromStr for Tuple<S, T> {
}
}
#[derive(Default)]
pub struct StringList(pub Vec<String>);
pub enum StringListParseError {

View File

@@ -2,7 +2,7 @@
name = "pci"
version = "0.1.0"
authors = ["Samuel Ortiz <sameo@linux.intel.com>"]
edition = "2021"
edition = "2018"
[features]
default = []
@@ -10,14 +10,14 @@ kvm = ["vfio-ioctls/kvm"]
mshv = ["vfio-ioctls/mshv"]
[dependencies]
anyhow = "1.0.56"
anyhow = "1.0.55"
byteorder = "1.4.3"
hypervisor = { path = "../hypervisor" }
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
vfio_user = { path = "../vfio_user" }
vmm-sys-util = "0.9.0"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
serde = "1.0.136"
serde_derive = "1.0.136"
thiserror = "1.0.30"

View File

@@ -201,13 +201,20 @@ impl MsiConfig {
devid: 0,
};
if let Err(e) = self.interrupt_source_group.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.cap.vector_masked(idx),
) {
if let Err(e) = self
.interrupt_source_group
.update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
{
error!("Failed updating vector: {:?}", e);
}
if self.cap.vector_masked(idx) {
if let Err(e) = self.interrupt_source_group.mask(idx as InterruptIndex) {
error!("Failed masking vector: {:?}", e);
}
} else if let Err(e) = self.interrupt_source_group.unmask(idx as InterruptIndex) {
error!("Failed unmasking vector: {:?}", e);
}
}
if !old_enabled {

View File

@@ -132,11 +132,7 @@ impl MsixConfig {
};
self.interrupt_source_group
.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
self.masked,
)
.update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
.map_err(Error::UpdateInterruptRoute)?;
self.interrupt_source_group
@@ -175,13 +171,21 @@ impl MsixConfig {
devid: self.devid,
};
if let Err(e) = self.interrupt_source_group.update(
idx as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
table_entry.masked(),
) {
if let Err(e) = self
.interrupt_source_group
.update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
{
error!("Failed updating vector: {:?}", e);
}
if table_entry.masked() {
if let Err(e) = self.interrupt_source_group.mask(idx as InterruptIndex) {
error!("Failed masking vector: {:?}", e);
}
} else if let Err(e) = self.interrupt_source_group.unmask(idx as InterruptIndex)
{
error!("Failed unmasking vector: {:?}", e);
}
}
} else if old_enabled || !old_masked {
debug!("MSI-X disabled for device 0x{:x}", self.devid);
@@ -310,10 +314,17 @@ impl MsixConfig {
if let Err(e) = self.interrupt_source_group.update(
index as InterruptIndex,
InterruptSourceConfig::MsiIrq(config),
table_entry.masked(),
) {
error!("Failed updating vector: {:?}", e);
}
if table_entry.masked() {
if let Err(e) = self.interrupt_source_group.mask(index as InterruptIndex) {
error!("Failed masking vector: {:?}", e);
}
} else if let Err(e) = self.interrupt_source_group.unmask(index as InterruptIndex) {
error!("Failed unmasking vector: {:?}", e);
}
}
// After the MSI-X table entry has been updated, it is necessary to

View File

@@ -506,10 +506,6 @@ impl Drop for VfioUserPciDevice {
if self.common.interrupt.intx_in_use() {
self.common.disable_intx(&self.vfio_wrapper);
}
if let Err(e) = self.client.lock().unwrap().shutdown() {
error!("Failed shutting down vfio-user client: {}", e);
}
}
}

View File

@@ -2,11 +2,11 @@
name = "performance-metrics"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
build = "build.rs"
[dependencies]
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
clap = { version = "3.1.5", features = ["wrap_help","cargo"] }
dirs = "4.0.0"
serde = { version = "1.0.136", features = ["rc"] }
serde_derive = "1.0.136"
@@ -16,4 +16,4 @@ thiserror = "1.0.30"
wait-timeout = "0.2.0"
[build-dependencies]
clap = { version = "3.1.8", features = ["cargo"] }
clap = { version = "3.1.5", features = ["wrap_help"] }

View File

@@ -22,6 +22,10 @@ enum Error {
TestTimeout,
#[error("Error: test failed")]
TestFailed,
#[error("Error creating log file: {0}")]
ReportFileCreation(std::io::Error),
#[error("Error writing log file: {0}")]
ReportFileWrite(std::io::Error),
}
#[derive(Deserialize, Serialize)]
@@ -136,7 +140,6 @@ struct PerformanceTest {
pub name: &'static str,
pub func_ptr: fn(&PerformanceTestControl) -> f64,
pub control: PerformanceTestControl,
unit_adjuster: fn(f64) -> f64,
}
impl PerformanceTest {
@@ -146,10 +149,10 @@ impl PerformanceTest {
metrics.push((self.func_ptr)(&self.control));
}
let mean = (self.unit_adjuster)(mean(&metrics).unwrap());
let std_dev = (self.unit_adjuster)(std_deviation(&metrics).unwrap());
let max = (self.unit_adjuster)(metrics.clone().into_iter().reduce(f64::max).unwrap());
let min = (self.unit_adjuster)(metrics.clone().into_iter().reduce(f64::min).unwrap());
let mean = mean(&metrics).unwrap();
let std_dev = std_deviation(&metrics).unwrap();
let max = metrics.clone().into_iter().reduce(f64::max).unwrap();
let min = metrics.clone().into_iter().reduce(f64::min).unwrap();
PerformanceTestResult {
name: self.name.to_string(),
@@ -197,45 +200,24 @@ fn std_deviation(data: &[f64]) -> Option<f64> {
}
}
mod adjuster {
pub fn identity(v: f64) -> f64 {
v
}
pub fn s_to_ms(v: f64) -> f64 {
v * 1000.0
}
pub fn bps_to_gbps(v: f64) -> f64 {
v / (1_000_000_000_f64)
}
#[allow(non_snake_case)]
pub fn Bps_to_MiBps(v: f64) -> f64 {
v / (1 << 20) as f64
}
}
const TEST_LIST: [PerformanceTest; 15] = [
PerformanceTest {
name: "boot_time_ms",
name: "boot_time_s",
func_ptr: performance_boot_time,
control: PerformanceTestControl {
test_timeout: 2,
test_iterations: 10,
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::s_to_ms,
},
PerformanceTest {
name: "boot_time_pmem_ms",
name: "boot_time_pmem_s",
func_ptr: performance_boot_time_pmem,
control: PerformanceTestControl {
test_timeout: 2,
test_iterations: 10,
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::s_to_ms,
},
PerformanceTest {
name: "virtio_net_latency_us",
@@ -245,10 +227,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
queue_size: Some(256),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::identity,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_rx_gbps",
name: "virtio_net_throughput_single_queue_rx_bps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -256,10 +237,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
net_rx: Some(true),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "virtio_net_throughput_single_queue_tx_gbps",
name: "virtio_net_throughput_single_queue_tx_bps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -267,10 +247,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
net_rx: Some(false),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_rx_gbps",
name: "virtio_net_throughput_multi_queue_rx_bps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
@@ -278,10 +257,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
net_rx: Some(true),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "virtio_net_throughput_multi_queue_tx_gbps",
name: "virtio_net_throughput_multi_queue_tx_bps",
func_ptr: performance_net_throughput,
control: PerformanceTestControl {
num_queues: Some(4),
@@ -289,10 +267,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
net_rx: Some(false),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::bps_to_gbps,
},
PerformanceTest {
name: "block_read_MiBps",
name: "block_read_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
@@ -300,10 +277,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::Read),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_write_MiBps",
name: "block_write_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
@@ -311,10 +287,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::Write),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_random_read_MiBps",
name: "block_random_read_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
@@ -322,10 +297,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::RandomRead),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_random_write_MiBps",
name: "block_random_write_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(1),
@@ -333,10 +307,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::RandomWrite),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_multi_queue_read_MiBps",
name: "block_multi_queue_read_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -344,10 +317,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::Read),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_multi_queue_write_MiBps",
name: "block_multi_queue_write_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -355,10 +327,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::Write),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_multi_queue_random_read_MiBps",
name: "block_multi_queue_random_read_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -366,10 +337,9 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::RandomRead),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
PerformanceTest {
name: "block_multi_queue_random_write_MiBps",
name: "block_multi_queue_random_write_Bps",
func_ptr: performance_block_io,
control: PerformanceTestControl {
num_queues: Some(2),
@@ -377,11 +347,10 @@ const TEST_LIST: [PerformanceTest; 15] = [
fio_ops: Some(FioOps::RandomWrite),
..PerformanceTestControl::default()
},
unit_adjuster: adjuster::Bps_to_MiBps,
},
];
fn run_test_with_timeout(test: &'static PerformanceTest) -> Result<PerformanceTestResult, Error> {
fn run_test_with_timetout(test: &'static PerformanceTest) -> Result<PerformanceTestResult, Error> {
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
thread::spawn(move || {
println!("Test '{}' running .. ({})", test.name, test.control);
@@ -447,16 +416,9 @@ fn main() {
)
.get_matches();
// It seems that the tool (ethr) used for testing the virtio-net latency
// is not stable on AArch64, and therefore the latency test is currently
// skipped on AArch64.
let test_list: Vec<&PerformanceTest> = TEST_LIST
.iter()
.filter(|t| !(cfg!(target_arch = "aarch64") && t.name == "virtio_net_latency_us"))
.collect();
if cmd_arguments.is_present("list-tests") {
for test in test_list.iter() {
println!("List of available metrics tests:\n");
for test in TEST_LIST.iter() {
println!("\"{}\" ({})", test.name, test.control);
}
@@ -468,20 +430,31 @@ fn main() {
None => Vec::new(),
};
let mut report_file: Box<dyn std::io::Write + Send> =
if let Some(file) = cmd_arguments.value_of("report-file") {
Box::new(
std::fs::File::create(std::path::Path::new(file))
.map_err(Error::ReportFileCreation)
.unwrap(),
)
} else {
Box::new(std::io::stderr())
};
// Run performance tests sequentially and report results (in both readable/json format)
let mut metrics_report: MetricsReport = Default::default();
init_tests();
for test in test_list.iter() {
for test in TEST_LIST.iter() {
if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) {
match run_test_with_timeout(test) {
match run_test_with_timetout(test) {
Ok(r) => {
metrics_report.results.push(r);
}
Err(e) => {
eprintln!("Aborting test due to error: '{:?}'", e);
std::process::exit(1);
break;
}
};
}
@@ -489,29 +462,13 @@ fn main() {
cleanup_tests();
let mut report_file: Box<dyn std::io::Write + Send> =
if let Some(file) = cmd_arguments.value_of("report-file") {
Box::new(
std::fs::File::create(std::path::Path::new(file))
.map_err(|e| {
eprintln!("Error opening report file: {}: {}", file, e);
std::process::exit(1);
})
.unwrap(),
)
} else {
Box::new(std::io::stdout())
};
// Todo: Report/upload to the metrics database
report_file
.write_all(
.write(
serde_json::to_string_pretty(&metrics_report)
.unwrap()
.as_bytes(),
)
.map_err(|e| {
eprintln!("Error writing report file: {}", e);
std::process::exit(1);
})
.map_err(Error::ReportFileWrite)
.unwrap();
}

View File

@@ -17,10 +17,7 @@ use test_infra::Error as InfraError;
use test_infra::*;
use wait_timeout::ChildExt;
#[cfg(target_arch = "x86_64")]
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
#[cfg(target_arch = "aarch64")]
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-0-update-tool.raw";
#[derive(Debug)]
enum WaitTimeoutError {
@@ -621,6 +618,7 @@ fn parse_fio_output(output: &str, fio_ops: &FioOps, num_jobs: u32) -> Result<f64
pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
let test_timeout = control.test_timeout;
let num_queues = control.num_queues.unwrap();
let queue_size = control.queue_size.unwrap();
let fio_ops = control.fio_ops.as_ref().unwrap();
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
@@ -638,20 +636,7 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
.args(&["--memory", "size=4G"])
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.args(&[
"--disk",
format!(
"path={}",
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
)
.as_str(),
format!(
"path={}",
guest.disk_config.disk(DiskType::CloudInit).unwrap()
)
.as_str(),
format!("path={}", BLK_IO_TEST_IMG).as_str(),
])
.default_disks()
.default_net()
.args(&["--api-socket", &api_socket])
.capture_output()
@@ -662,6 +647,25 @@ pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
// Hotplug test disk
assert!(Command::new(clh_command("ch-remote"))
.args(&[&format!("--api-socket={}", api_socket)])
.args(&[
"add-disk",
&format!(
"path={},num_queues={},queue_size={},direct=on",
BLK_IO_TEST_IMG, num_queues, queue_size
)
])
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap()
.wait_timeout(Duration::from_secs(5))
.unwrap()
.expect("Failed to hotplug test disk image")
.success());
let fio_command = format!(
"sudo fio --filename=/dev/vdc --name=test --output-format=json \
--direct=1 --bs=4k --ioengine=io_uring --iodepth=64 \

View File

@@ -2,7 +2,7 @@
name = "qcow"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2021"
edition = "2018"
license = "BSD-3-Clause"
[lib]
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
[dependencies]
byteorder = "1.4.3"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
remain = "0.2.2"
vmm-sys-util = "0.9.0"

View File

@@ -1,9 +1,9 @@
[package]
name = "rate_limiter"
version = "0.1.0"
edition = "2021"
edition = "2018"
[dependencies]
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
vmm-sys-util = "0.9.0"

View File

@@ -1,12 +1,3 @@
- [v23.1](#v231)
- [v23.0](#v230)
- [vDPA Support](#vdpa-support)
- [Updated OS Support list](#updated-os-support-list)
- [`AArch64` Memory Map Improvements](#aarch64-memory-map-improvements)
- [`AMX` Support](#amx-support)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Deprecations](#deprecations)
- [Contributors](#contributors)
- [v22.1](#v221)
- [v22.0](#v220)
- [GDB Debug Stub Support](#gdb-debug-stub-support)
@@ -17,13 +8,13 @@
- [PMU Support for AArch64](#pmu-support-for-aarch64)
- [Documentation Under CC-BY-4.0 License](#documentation-under-cc-by-40-license)
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
- [Notable Bug Fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [Notable Bug Fixes](#notable-bug-fixes)
- [Contributors](#contributors)
- [v21.0](#v210)
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
- [Notable Bug fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [Notable Bug fixes](#notable-bug-fixes-1)
- [Contributors](#contributors-1)
- [v20.2](#v202)
- [v20.1](#v201)
- [v20.0](#v200)
@@ -32,8 +23,8 @@
- [Improved VFIO support](#improved-vfio-support)
- [Safer code](#safer-code)
- [Extended documentation](#extended-documentation)
- [Notable bug fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [Notable bug fixes](#notable-bug-fixes-2)
- [Contributors](#contributors-2)
- [v19.0](#v190)
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
- [PCI boot time optimisations](#pci-boot-time-optimisations)
@@ -41,8 +32,8 @@
- [Live migration enhancements](#live-migration-enhancements)
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
- [Notable bug fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-4)
- [Notable bug fixes](#notable-bug-fixes-3)
- [Contributors](#contributors-3)
- [v18.0](#v180)
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
@@ -52,31 +43,31 @@
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
- [Power button support on AArch64](#power-button-support-on-aarch64)
- [Notable bug fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-5)
- [Notable bug fixes](#notable-bug-fixes-4)
- [Contributors](#contributors-4)
- [v17.0](#v170)
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
- [Improved SGX support](#improved-sgx-support)
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
- [Notable bug fixes](#notable-bug-fixes-6)
- [Contributors](#contributors-6)
- [Notable bug fixes](#notable-bug-fixes-5)
- [Contributors](#contributors-5)
- [v16.0](#v160)
- [Improved live migration support](#improved-live-migration-support)
- [Improved `vhost-user` support](#improved-vhost-user-support)
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
- [Notable bug fixes](#notable-bug-fixes-7)
- [Notable bug fixes](#notable-bug-fixes-6)
- [Removed functionality](#removed-functionality)
- [Contributors](#contributors-7)
- [Contributors](#contributors-6)
- [v15.0](#v150)
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
- [Network device rate limiting](#network-device-rate-limiting)
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
- [Bug fixes](#bug-fixes)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-8)
- [Deprecations](#deprecations)
- [Contributors](#contributors-7)
- [v0.14.1](#v0141)
- [v0.14.0](#v0140)
- [Structured event monitoring](#structured-event-monitoring)
@@ -85,8 +76,8 @@
- [Updated hotplug documentation](#updated-hotplug-documentation)
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
- [Block device rate limiting](#block-device-rate-limiting)
- [Deprecations](#deprecations-2)
- [Contributors](#contributors-9)
- [Deprecations](#deprecations-1)
- [Contributors](#contributors-8)
- [v0.13.0](#v0130)
- [Wider VFIO device support](#wider-vfio-device-support)
- [Improved huge page support](#improved-huge-page-support)
@@ -94,13 +85,13 @@
- [VHD disk image support](#vhd-disk-image-support)
- [Improved Virtio device threading](#improved-virtio-device-threading)
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
- [Contributors](#contributors-10)
- [Contributors](#contributors-9)
- [v0.12.0](#v0120)
- [ARM64 enhancements](#arm64-enhancements)
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
- [Enhanced "info" API](#enhanced-info-api)
- [Contributors](#contributors-11)
- [Contributors](#contributors-10)
- [v0.11.0](#v0110)
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
- [Windows Guest Support](#windows-guest-support)
@@ -112,15 +103,15 @@
- [Default Log Level Changed](#default-log-level-changed)
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-12)
- [Notable Bug Fixes](#notable-bug-fixes-7)
- [Contributors](#contributors-11)
- [v0.10.0](#v0100)
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
- [Memory Zones](#memory-zones)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-13)
- [Notable Bug Fixes](#notable-bug-fixes-8)
- [Contributors](#contributors-12)
- [v0.9.0](#v090)
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
- [Block and Network Device Statistics](#block-and-network-device-statistics)
@@ -133,17 +124,17 @@
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
- [Intel SGX Support](#intel-sgx-support)
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Contributors](#contributors-14)
- [Notable Bug Fixes](#notable-bug-fixes-9)
- [Contributors](#contributors-13)
- [v0.8.0](#v080)
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
- [Experimental ARM64 Support](#experimental-arm64-support)
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
- [Notable Bug Fixes](#notable-bug-fixes-11)
- [Notable Bug Fixes](#notable-bug-fixes-10)
- [Command Line and API Changes](#command-line-and-api-changes)
- [Contributors](#contributors-15)
- [Contributors](#contributors-14)
- [v0.7.0](#v070)
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
- [Alternative `libc` Support](#alternative-libc-support)
@@ -153,14 +144,14 @@
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
- [Updated Distribution Support](#updated-distribution-support)
- [Command Line and API Changes](#command-line-and-api-changes-1)
- [Contributors](#contributors-16)
- [Contributors](#contributors-15)
- [v0.6.0](#v060)
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
- [Command Line Interface](#command-line-interface)
- [PVH Boot](#pvh-boot)
- [Contributors](#contributors-17)
- [Contributors](#contributors-16)
- [v0.5.1](#v051)
- [v0.5.0](#v050)
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
@@ -168,7 +159,7 @@
- [New Interrupt Management Framework](#new-interrupt-management-framework)
- [Development Tools](#development-tools)
- [Kata Containers Integration](#kata-containers-integration)
- [Contributors](#contributors-18)
- [Contributors](#contributors-17)
- [v0.4.0](#v040)
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
@@ -177,7 +168,7 @@
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
- [PCI BAR reprogramming](#pci-bar-reprogramming)
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
- [Contributors](#contributors-19)
- [Contributors](#contributors-18)
- [v0.3.0](#v030)
- [Block device offloading](#block-device-offloading)
- [Network device backend](#network-device-backend)
@@ -203,79 +194,6 @@
- [Console over virtio](#console-over-virtio)
- [Unit testing](#unit-testing)
- [Integration tests parallelization](#integration-tests-parallelization)
# v23.1
This is a bug fix release. The following issues have been addressed:
* Add some missing seccomp rules
* Remove `virtio-fs` filesystem entries from config on removal
* Do not delete API socket on API server start (#4026)
* Reject `virtio-mem` resize if the guest doesn't activate the device
* Fix OpenAPI naming of I/O throttling knobs
# v23.0
This release has been tracked through the [v23.0
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/27).
### vDPA Support
A vDPA device has a datapath that complies with the virtio specification but
with a vendor specific control path. The addition of `--vdpa` and the REST API
equivalent allows the use of these devices with Cloud Hypervisor.
### Updated OS Support list
The list of officially supported and tested OS versions has been updated to
include Ubuntu "jammy" 22.04 and EOLed versions removed.
### `AArch64` Memory Map Improvements
The memory map when running on `AArch64` has been improved for the handling of
the UEFI region which means that the booted guest OS now has full access to its
allocated RAM. (#3938)
### `AMX` Support
Under a compile time gate of `amx` it is possible compile in support for the
`AMX` instruction set extension for guest use. This also requires runtime
enabling with `--cpu features=amx`.
### Notable Bug Fixes
* Generate error when incorrect HTTP method used for some API endpoints (#3887)
* CMOS based reset is now available to support rebooting on "jammy" (#3914)
* ACPI tables are not produced for memory hotplug when running with
`virtio-mem` (#3883)
* `virtio-iommu` backed PCI segments are now comprehensively placed behind the
vIOMMU (#3870)
* Seccomp rules have been extended for `virtio-fs` to support direct access
(#3848)
### Deprecations
Deprecated features will be removed in a subsequent release and users should
plan to use alternatives
* The `mergeable` option from the `virtio-pmem` support has been deprecated
(#3968)
* The `dax` option from the `virtio-fs` support has been deprecated (#3889)
### Contributors
Many thanks to everyone who has contributed to our release:
* Bo Chen <chen.bo@intel.com>
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
* Henry Wang <Henry.Wang@arm.com>
* Jianyong Wu <jianyong.wu@arm.com>
* LiHui <andrewli@kubesphere.io>
* Michael Zhao <michael.zhao@arm.com>
* Rob Bradford <robert.bradford@intel.com>
* Sebastien Boeuf <sebastien.boeuf@intel.com>
* Wei Liu <liuwe@microsoft.com>
* William Douglas <william.douglas@intel.com>
* Yi Wang <wang.yi59@zte.com.cn>
# v22.1
@@ -296,6 +214,7 @@ by the `gdb` compile time feature and details of how to use it can be found in
the [gdb
documentation](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/gdb.md).
### `virtio-iommu` Backed Segments
In order to facilitate hotplug devices that require being behind an IOMMU (e.g.
@@ -307,6 +226,7 @@ will place all the specified segments behind the IOMMU.
It is now possible to change the VM configuration (e.g. add or remove devices,
resize) before the VM is booted.
### `virtio-balloon` Free Page Reporting
If `--balloon free_page_reporting=on` is used then the guest can report pages

View File

@@ -112,7 +112,7 @@ RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
RUN if [ "$TARGETARCH" = "amd64" ]; then \
git clone https://github.com/spdk/spdk \
&& cd spdk \
&& git checkout 6301f8915de32baed10dba1eebed556a6749211a \
&& git checkout 59f3cdacb13bd2a19c4a86be04792b0ee4491172 \
&& git submodule update --init \
&& apt-get update \
&& ./scripts/pkgdep.sh \

View File

@@ -9,7 +9,7 @@
Name: cloud-hypervisor
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
Version: 23.1
Version: 22.1
Release: 0%{?dist}
License: ASL 2.0 or BSD-3-clause
Group: Applications/System
@@ -112,11 +112,8 @@ rm -rf %{buildroot}
%changelog
* Mon May 09 2022 Rob Bradford <robert.bradford@intel.com> 23.1-0
- Update to 23.1
* Thu Apr 13 2022 Rob Bradford <robert.bradford@intel.com> 23.0-0
- Update to 23.0
* Thu Mar 10 2022 Rob Bradford <robert.bradford@intel.com> 22.1-0
- Update to 22.1
* Thu Mar 03 2022 Rob Bradford <robert.bradford@intel.com> 22.0-0
- Update to 22.0

View File

@@ -7,7 +7,7 @@
CLI_NAME="Cloud Hypervisor"
CTR_IMAGE_TAG="cloudhypervisor/dev"
CTR_IMAGE_VERSION="20220405-0"
CTR_IMAGE_VERSION="20220303-0"
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
DOCKER_RUNTIME="docker"
@@ -183,9 +183,10 @@ cmd_help() {
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
echo ""
echo " tests [<test type (see below)>] [--libc musl|gnu] [-- [<test scripts args>] [-- [<test binary args>]]] "
echo " tests [--unit|--cargo|--all] [--libc musl|gnu] [-- [<test scripts args>] [-- [<test binary args>]]] "
echo " Run the Cloud Hypervisor tests."
echo " --unit Run the unit tests."
echo " --cargo Run the cargo tests."
echo " --integration Run the integration tests."
echo " --integration-sgx Run the SGX integration tests."
echo " --integration-vfio Run the VFIO integration tests."
@@ -270,6 +271,8 @@ cmd_build() {
cargo_args=("$@")
[ $build = "release" ] && cargo_args+=("--release")
cargo_args+=(--target "$target")
[ "$(uname -m)" = "aarch64" ] && cargo_args+=("--no-default-features")
[ "$(uname -m)" = "aarch64" ] && cargo_args+=(--features "$hypervisor")
rustflags=""
target_cc=""
@@ -311,6 +314,7 @@ cmd_clean() {
cmd_tests() {
unit=false
cargo=false
integration=false
integration_sgx=false
integration_vfio=false
@@ -328,6 +332,7 @@ cmd_tests() {
exit 1
} ;;
"--unit") { unit=true; } ;;
"--cargo") { cargo=true; } ;;
"--integration") { integration=true; } ;;
"--integration-sgx") { integration_sgx=true; } ;;
"--integration-vfio") { integration_vfio=true; } ;;
@@ -393,6 +398,16 @@ cmd_tests() {
./scripts/run_unit_tests.sh "$@" || fix_dir_perms $? || exit $?
fi
if [ "$cargo" = true ]; then
say "Running cargo tests..."
$DOCKER_RUNTIME run \
--workdir "$CTR_CLH_ROOT_DIR" \
--rm \
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
"$CTR_IMAGE" \
./scripts/run_cargo_tests.sh "$@" || fix_dir_perms $? || exit $?
fi
if [ "$integration" = true ]; then
say "Running integration tests for $target..."
$DOCKER_RUNTIME run \

View File

@@ -1,42 +0,0 @@
#!/bin/bash
set -x
sudo apt install -y libncurses-dev gawk flex bison openssl libssl-dev dkms libelf-dev libudev-dev libpci-dev libiberty-dev autoconf git make dpkg-dev libmnl-dev pkg-config
sudo sed -i -- 's/# deb-src/deb-src/g' /etc/apt/sources.list
sudo apt update
apt-get source linux-image-unsigned-`uname -r`
pushd linux-azure*/drivers/vdpa/vdpa_sim/
cat <<'EOF' > Makefile
# SPDX-License-Identifier: GPL-2.0
obj-m += vdpa_sim.o
obj-m += vdpa_sim_net.o
obj-m += vdpa_sim_blk.o
EOF
make -C /lib/modules/`uname -r`/build M=$PWD
sudo make -C /lib/modules/`uname -r`/build M=$PWD modules_install
popd
sudo depmod -a
sudo modprobe vdpa
sudo modprobe vhost_vdpa
sudo modprobe vdpa_sim
sudo modprobe vdpa_sim_blk
sudo modprobe vdpa_sim_net
# After the Jenkins builder are moved to Ubuntu 22.04, manually building and
# installing iproute2/vdpa won't be required.
# Tracked by: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/3862
git clone https://github.com/shemminger/iproute2.git
pushd iproute2
./configure
make -j
sudo make install
popd
# Create /dev/vhost-vdpa-0
sudo vdpa dev add name vdpa-blk1 mgmtdev vdpasim_blk
# Create /dev/vhost-vdpa-1
sudo vdpa dev add name vdpa-blk2 mgmtdev vdpasim_blk
# Create /dev/vhost-vdpa-2
sudo vdpa dev add name vdpa-net1 mgmtdev vdpasim_net
sudo chmod 660 /dev/vhost-vdpa-0
sudo chmod 660 /dev/vhost-vdpa-1
sudo chmod 660 /dev/vhost-vdpa-2
vdpa dev show -jp

26
scripts/run_cargo_tests.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/bin/bash
set -e
set -x
source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh
process_common_args "$@"
# Install cargo components
time rustup component add clippy
time rustup component add rustfmt
time which cargo-audit || cargo install cargo-audit
# Run cargo builds and checks
time cargo clippy --all-targets --all-features -- -D warnings
time cargo rustc --bin cloud-hypervisor -- -D warnings
time cargo rustc -p vhost_user_net --bin vhost_user_net -- -D warnings
time cargo test
time cargo audit
time cargo clippy --all-targets --no-default-features --features "acpi,$hypervisor" -- -D warnings
time cargo rustc --bin cloud-hypervisor --no-default-features --features "acpi,$hypervisor" -- -D warnings
time cargo clippy --all-targets --no-default-features --features "$hypervisor" -- -D warnings
time cargo rustc --bin cloud-hypervisor --no-default-features --features "$hypervisor" -- -D warnings
time cargo fmt -- --check
time cargo build --all --release

View File

@@ -11,6 +11,63 @@ WORKLOADS_LOCK="$WORKLOADS_DIR/integration_test.lock"
mkdir -p "$WORKLOADS_DIR"
# Checkout source code of a GIT repo with specified branch and commit
# Args:
# $1: Target directory
# $2: GIT URL of the repo
# $3: Required branch
# $4: Required commit (optional)
checkout_repo() {
SRC_DIR="$1"
GIT_URL="$2"
GIT_BRANCH="$3"
GIT_COMMIT="$4"
# Check whether the local HEAD commit same as the requested commit or not.
# If commit is not specified, compare local HEAD and remote HEAD.
# Remove the folder if there is difference.
if [ -d "$SRC_DIR" ]; then
pushd $SRC_DIR
git fetch
SRC_LOCAL_COMMIT=$(git rev-parse HEAD)
if [ -z "$GIT_COMMIT" ]; then
GIT_COMMIT=$(git rev-parse remotes/origin/"$GIT_BRANCH")
fi
popd
if [ "$SRC_LOCAL_COMMIT" != "$GIT_COMMIT" ]; then
rm -rf "$SRC_DIR"
fi
fi
# Checkout the specified branch and commit (if required)
if [ ! -d "$SRC_DIR" ]; then
git clone --depth 1 "$GIT_URL" -b "$GIT_BRANCH" "$SRC_DIR"
if [ "$GIT_COMMIT" ]; then
pushd "$SRC_DIR"
git fetch --depth 1 origin "$GIT_COMMIT"
git reset --hard FETCH_HEAD
popd
fi
fi
}
build_custom_linux() {
SRCDIR=$PWD
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
LINUX_CUSTOM_BRANCH="ch-5.15.12"
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
cp $SRCDIR/resources/linux-config-aarch64 $LINUX_CUSTOM_DIR/.config
pushd $LINUX_CUSTOM_DIR
time make -j `nproc`
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
popd
}
build_edk2() {
EDK2_BUILD_DIR="$WORKLOADS_DIR/edk2_build"
EDK2_REPO="https://github.com/tianocore/edk2.git"
@@ -35,61 +92,33 @@ build_edk2() {
checkout_repo "$EDK2_PLAT_DIR" "$EDK2_PLAT_REPO" master "8227e9e9f6a8aefbd772b40138f835121ccb2307"
checkout_repo "$ACPICA_DIR" "$ACPICA_REPO" master "b9c69f81a05c45611c91ea9cbce8756078d76233"
if [[ ! -f "$EDK2_DIR/.built" || \
! -f "$EDK2_PLAT_DIR/.built" || \
! -f "$ACPICA_DIR/.built" ]]; then
pushd "$EDK2_BUILD_DIR"
# Build
make -C acpica -j `nproc`
source edk2/edksetup.sh
make -C edk2/BaseTools -j `nproc`
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE -n 0
cp Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd "$WORKLOADS_DIR"
touch "$EDK2_DIR"/.built
touch "$EDK2_PLAT_DIR"/.built
touch "$ACPICA_DIR"/.built
popd
fi
pushd "$EDK2_BUILD_DIR"
# Build
make -C acpica -j `nproc`
source edk2/edksetup.sh
make -C edk2/BaseTools -j `nproc`
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtCloudHv.dsc -b RELEASE -n 0
cp Build/ArmVirtCloudHv-AARCH64/RELEASE_GCC5/FV/CLOUDHV_EFI.fd "$WORKLOADS_DIR"
popd
}
build_spdk_nvme() {
SPDK_DIR="$WORKLOADS_DIR/spdk"
SPDK_REPO="https://github.com/spdk/spdk.git"
SPDK_DEPLOY_DIR="/usr/local/bin/spdk-nvme"
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "6301f8915de32baed10dba1eebed556a6749211a"
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "f9c496b8e21a8f499df268818bf8b5d8e2b19f04"
if [ ! -f "$SPDK_DIR/.built" ]; then
pushd $SPDK_DIR
git submodule update --init
apt-get update
./scripts/pkgdep.sh
./configure --with-vfio-user
chmod +x /usr/local/lib/python3.8/dist-packages/ninja/data/bin/ninja
make -j `nproc` || exit 1
touch .built
popd
fi
if [ ! -d "/usr/local/bin/spdk-nvme" ]; then
mkdir -p $SPDK_DEPLOY_DIR
fi
cp "$WORKLOADS_DIR/spdk/build/bin/nvmf_tgt" $SPDK_DEPLOY_DIR/nvmf_tgt
cp "$WORKLOADS_DIR/spdk/scripts/rpc.py" $SPDK_DEPLOY_DIR/rpc.py
cp -r "$WORKLOADS_DIR/spdk/scripts/rpc" $SPDK_DEPLOY_DIR/rpc
}
build_virtiofsd() {
VIRTIOFSD_DIR="$WORKLOADS_DIR/virtiofsd_build"
VIRTIOFSD_REPO="https://gitlab.com/virtio-fs/virtiofsd.git"
checkout_repo "$VIRTIOFSD_DIR" "$VIRTIOFSD_REPO" v1.1.0 "220405d7a2606c92636d31992b5cb3036a41047b"
if [ ! -f "$VIRTIOFSD_DIR/.built" ]; then
pushd $VIRTIOFSD_DIR
time cargo build --release
cp target/release/virtiofsd "$WORKLOADS_DIR/" || exit 1
touch .built
popd
fi
pushd $SPDK_DIR
git submodule update --init
apt-get update
./scripts/pkgdep.sh
./configure --with-vfio-user
chmod +x /usr/local/lib/python3.8/dist-packages/ninja/data/bin/ninja
make -j `nproc`
mkdir /usr/local/bin/spdk-nvme
cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme
cp ./scripts/rpc.py /usr/local/bin/spdk-nvme
cp -r ./scripts/rpc /usr/local/bin/spdk-nvme
popd
}
update_workloads() {
@@ -140,24 +169,6 @@ update_workloads() {
popd
fi
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="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL || exit 1
popd
fi
JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="jammy-server-cloudimg-arm64-custom-20220329-0.qcow2"
JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
if [ ! -f "$JAMMY_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL || exit 1
popd
fi
ALPINE_MINIROOTFS_URL="http://dl-cdn.alpinelinux.org/alpine/v3.11/releases/aarch64/alpine-minirootfs-3.11.3-aarch64.tar.gz"
ALPINE_MINIROOTFS_TARBALL="$WORKLOADS_DIR/alpine-minirootfs-aarch64.tar.gz"
if [ ! -f "$ALPINE_MINIROOTFS_TARBALL" ]; then
@@ -206,7 +217,19 @@ update_workloads() {
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
# Build virtiofsd
build_virtiofsd
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
VIRTIOFSD_DIR="virtiofsd_build"
if [ ! -f "$VIRTIOFSD" ]; then
pushd $WORKLOADS_DIR
git clone "https://gitlab.com/virtio-fs/virtiofsd.git" $VIRTIOFSD_DIR
pushd $VIRTIOFSD_DIR
git checkout v1.1.0
time cargo build --release
cp target/release/virtiofsd $VIRTIOFSD || exit 1
popd
rm -rf $VIRTIOFSD_DIR
popd
fi
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
MNT_DIR="mount_image"
@@ -229,10 +252,10 @@ update_workloads() {
echo "bar" > "$SHARED_DIR/file3" || exit 1
fi
# Checkout and build SPDK NVMe
# checkout and build SPDK NVMe
build_spdk_nvme
# Checkout and build EDK2
# Check and build EDK2 binary
build_edk2
}

View File

@@ -71,23 +71,6 @@ if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
popd
fi
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20220329-0.qcow2"
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
pushd $WORKLOADS_DIR
time wget --quiet $JAMMY_OS_IMAGE_URL || exit 1
popd
fi
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20220329-0.raw"
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
pushd $WORKLOADS_DIR
time qemu-img convert -p -f qcow2 -O raw $JAMMY_OS_IMAGE_NAME $JAMMY_OS_RAW_IMAGE_NAME || exit 1
popd
fi
ALPINE_MINIROOTFS_URL="http://dl-cdn.alpinelinux.org/alpine/v3.11/releases/x86_64/alpine-minirootfs-3.11.3-x86_64.tar.gz"
ALPINE_MINIROOTFS_TARBALL="$WORKLOADS_DIR/alpine-minirootfs-x86_64.tar.gz"
if [ ! -f "$ALPINE_MINIROOTFS_TARBALL" ]; then
@@ -124,7 +107,27 @@ popd
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
build_custom_linux
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then
SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
VIRTIOFSD_DIR="virtiofsd_build"
@@ -187,13 +190,10 @@ sudo bash -c "echo 1000000 > /sys/kernel/mm/ksm/pages_to_scan"
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
# Both test_vfio, ovs-dpdk and vDPA tests rely on hugepages
# Both test_vfio and ovs-dpdk rely on hugepages
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
# Update max locked memory to 'unlimited' to avoid issues with vDPA
ulimit -l unlimited
export RUST_BACKTRACE=1
time cargo test $features "parallel::$test_filter" -- ${test_binary_args[*]}
RES=$?

View File

@@ -4,45 +4,23 @@ set -x
source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh
export TEST_ARCH=$(uname -m)
export BUILD_TARGET=${BUILD_TARGET-${TEST_ARCH}-unknown-linux-gnu}
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
WORKLOADS_DIR="$HOME/workloads"
mkdir -p "$WORKLOADS_DIR"
build_fio() {
FIO_DIR="$WORKLOADS_DIR/fio_build"
FIO_REPO="https://github.com/axboe/fio.git"
checkout_repo "$FIO_DIR" "$FIO_REPO" master "1953e1adb5a28ed21370e85991d7f5c3cdc699f3"
if [ ! -f "$FIO_DIR/.built" ]; then
pushd $FIO_DIR
./configure
make -j `nproc`
cp fio "$WORKLOADS_DIR/fio"
touch .built
popd
fi
}
process_common_args "$@"
# For now these values are default for kvm
features=""
if [ "$hypervisor" = "mshv" ]; then
if [ "$hypervisor" = "mshv" ] ; then
features="--no-default-features --features mshv,common"
fi
cp scripts/sha1sums-${TEST_ARCH} $WORKLOADS_DIR
if [ ${TEST_ARCH} == "aarch64" ]; then
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
else
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
fi
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
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"
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
@@ -51,12 +29,7 @@ if [ ! -f "$FOCAL_OS_IMAGE" ]; then
popd
fi
if [ ${TEST_ARCH} == "aarch64" ]; then
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw"
else
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
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
@@ -65,38 +38,43 @@ if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
fi
pushd $WORKLOADS_DIR
grep focal sha1sums-${TEST_ARCH} | sha1sum --check
grep focal sha1sums-x86_64 | sha1sum --check
if [ $? -ne 0 ]; then
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
exit 1
fi
popd
if [ ${TEST_ARCH} == "aarch64" ]; then
build_fio
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
# Update the fio in the cloud image to use io_uring on AArch64
FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_NAME="focal-server-cloudimg-arm64-custom-20210929-0-update-tool.raw"
cp "$FOCAL_OS_RAW_IMAGE" "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_NAME"
FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR="$WORKLOADS_DIR/focal-server-cloudimg-root"
if [ ! -d "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR" ]; then
mkdir -p "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR"
fi
# Mount the 'raw' image, replace the fio and umount the working folder
guestmount -a "$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_NAME" -m /dev/sda1 "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR" || exit 1
cp "$WORKLOADS_DIR"/fio "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR"/usr/bin/fio
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_TOOL_ROOT_DIR"
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
if [ ! -f "$VMLINUX_IMAGE" ]; then
SRCDIR=$PWD
pushd $WORKLOADS_DIR
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
popd
fi
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
build_custom_linux
if [ ! -f "$VMLINUX_IMAGE" ]; then
pushd $LINUX_CUSTOM_DIR
time make bzImage -j `nproc`
cp vmlinux $VMLINUX_IMAGE || exit 1
popd
fi
BUILD_TARGET="${TEST_ARCH}-unknown-linux-${CH_LIBC}"
if [ -d "$LINUX_CUSTOM_DIR" ]; then
rm -rf $LINUX_CUSTOM_DIR
fi
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
CFLAGS=""
TARGET_CC=""
if [[ "${BUILD_TARGET}" == "${TEST_ARCH}-unknown-linux-musl" ]]; then
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
TARGET_CC="musl-gcc"
CFLAGS="-I /usr/include/${TEST_ARCH}-linux-musl/ -idirafter /usr/include/"
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
fi
cargo build --all --release $features --target $BUILD_TARGET
@@ -109,10 +87,6 @@ strip target/$BUILD_TARGET/release/performance-metrics
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
sudo chmod a+rwX /dev/hugepages
if [ -n "$test_filter" ]; then
test_binary_args+=("--test-filter $test_filter")
fi
export RUST_BACKTRACE=1
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
RES=$?

View File

@@ -1,16 +1,16 @@
#!/bin/bash
source $HOME/.cargo/env
source $(dirname "$0")/test-util.sh
source $(dirname "$0")/test-util.sh
process_common_args "$@"
BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
cargo_args=("")
if [[ $hypervisor = "mshv" ]]; then
if [[ $(uname -m) = "aarch64" || $hypervisor = "mshv" ]]; then
cargo_args+=("--no-default-features")
cargo_args+=("--features common,$hypervisor")
cargo_args+=("--features $hypervisor")
fi
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
@@ -19,4 +19,4 @@ if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
fi
export RUST_BACKTRACE=1
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1;

View File

@@ -4,5 +4,3 @@
e4addb6e212a298144f9eb0eb6e36019d013f0e7 alpine-minirootfs-aarch64.tar.gz
25b4f9ac308898d63b73d7db0e0e2d4768853723 focal-server-cloudimg-arm64-custom-20210929-0.qcow2
9953b31bb1923cdd8d91b1b7cc9ad3a9be1e0a59 focal-server-cloudimg-arm64-custom-20210929-0.raw
7118f4d4cad18c8357bc2ad9824a50f9a82a860a jammy-server-cloudimg-arm64-custom-20220329-0.qcow2
1f2b71be43b8f748f01306c4454e5c921343faa4 jammy-server-cloudimg-arm64-custom-20220329-0.raw

View File

@@ -3,5 +3,3 @@
d4a44acc6014d5f83dea1c625c43d677a95fa75f alpine-minirootfs-x86_64.tar.gz
f1eccdc5e1b515dbad294426ab081b47ebfb97c0 focal-server-cloudimg-amd64-custom-20210609-0.qcow2
7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw
272102ac243e544bc5c2303f383eeb217bd2e446 jammy-server-cloudimg-amd64-custom-20220329-0.qcow2
0b5b4816a0976c458f8e8bab061e9d63ebc1b806 jammy-server-cloudimg-amd64-custom-20220329-0.raw

View File

@@ -1,68 +1,7 @@
#!/bin/bash
hypervisor="kvm"
test_filter=""
# Checkout source code of a GIT repo with specified branch and commit
# Args:
# $1: Target directory
# $2: GIT URL of the repo
# $3: Required branch
# $4: Required commit (optional)
checkout_repo() {
SRC_DIR="$1"
GIT_URL="$2"
GIT_BRANCH="$3"
GIT_COMMIT="$4"
# Check whether the local HEAD commit same as the requested commit or not.
# If commit is not specified, compare local HEAD and remote HEAD.
# Remove the folder if there is difference.
if [ -d "$SRC_DIR" ]; then
pushd $SRC_DIR
git fetch
SRC_LOCAL_COMMIT=$(git rev-parse HEAD)
if [ -z "$GIT_COMMIT" ]; then
GIT_COMMIT=$(git rev-parse remotes/origin/"$GIT_BRANCH")
fi
popd
if [ "$SRC_LOCAL_COMMIT" != "$GIT_COMMIT" ]; then
rm -rf "$SRC_DIR"
fi
fi
# Checkout the specified branch and commit (if required)
if [ ! -d "$SRC_DIR" ]; then
git clone --depth 1 "$GIT_URL" -b "$GIT_BRANCH" "$SRC_DIR"
if [ "$GIT_COMMIT" ]; then
pushd "$SRC_DIR"
git fetch --depth 1 origin "$GIT_COMMIT"
git reset --hard FETCH_HEAD
popd
fi
fi
}
build_custom_linux() {
ARCH=$(uname -m)
SRCDIR=$PWD
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
LINUX_CUSTOM_BRANCH="ch-5.15.12"
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
cp $SRCDIR/resources/linux-config-${ARCH} $LINUX_CUSTOM_DIR/.config
pushd $LINUX_CUSTOM_DIR
make -j `nproc`
if [ ${ARCH} == "x86_64" ]; then
cp vmlinux "$WORKLOADS_DIR/" || exit 1
elif [ ${ARCH} == "aarch64" ]; then
cp arch/arm64/boot/Image "$WORKLOADS_DIR/" || exit 1
cp arch/arm64/boot/Image.gz "$WORKLOADS_DIR/" || exit 1
fi
popd
}
test_binary_args=()
cmd_help() {
echo ""
@@ -105,5 +44,5 @@ process_common_args() {
die "Hypervisor value must be kvm or mshv"
fi
test_binary_args=($@)
test_binary_args="$@"
}

View File

@@ -28,7 +28,6 @@ enum Error {
AddPmemConfig(vmm::config::Error),
AddNetConfig(vmm::config::Error),
AddUserDeviceConfig(vmm::config::Error),
AddVdpaConfig(vmm::config::Error),
AddVsockConfig(vmm::config::Error),
Restore(vmm::config::Error),
}
@@ -48,7 +47,6 @@ impl fmt::Display for Error {
AddPmemConfig(e) => write!(f, "Error parsing persistent memory syntax: {}", e),
AddNetConfig(e) => write!(f, "Error parsing network syntax: {}", e),
AddUserDeviceConfig(e) => write!(f, "Error parsing user device syntax: {}", e),
AddVdpaConfig(e) => write!(f, "Error parsing vDPA device syntax: {}", e),
AddVsockConfig(e) => write!(f, "Error parsing vsock syntax: {}", e),
Restore(e) => write!(f, "Error parsing restore syntax: {}", e),
}
@@ -214,18 +212,6 @@ fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
.map_err(Error::ApiClient)
}
fn add_vdpa_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
let vdpa_config = vmm::config::VdpaConfig::parse(config).map_err(Error::AddVdpaConfig)?;
simple_api_command(
socket,
"PUT",
"add-vdpa",
Some(&serde_json::to_string(&vdpa_config).unwrap()),
)
.map_err(Error::ApiClient)
}
fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
let vsock_config = vmm::config::VsockConfig::parse(config).map_err(Error::AddVsockConfig)?;
@@ -390,14 +376,6 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
.value_of("device_config")
.unwrap(),
),
Some("add-vdpa") => add_vdpa_api_command(
&mut socket,
matches
.subcommand_matches("add-vdpa")
.unwrap()
.value_of("vdpa_config")
.unwrap(),
),
Some("add-vsock") => add_vsock_api_command(
&mut socket,
matches
@@ -508,13 +486,6 @@ fn main() {
.help(vmm::config::UserDeviceConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-vdpa").about("Add vDPA device").arg(
Arg::new("vdpa_config")
.index(1)
.help(vmm::config::VdpaConfig::SYNTAX),
),
)
.subcommand(
Command::new("add-vsock").about("Add vsock device").arg(
Arg::new("vsock_config")

View File

@@ -13,12 +13,16 @@ use libc::EFD_NONBLOCK;
use log::LevelFilter;
use option_parser::OptionParser;
use seccompiler::SeccompAction;
use signal_hook::consts::SIGSYS;
use signal_hook::{
consts::SIGSYS,
iterator::{exfiltrator::WithRawSiginfo, SignalsInfo},
};
use std::env;
use std::fs::File;
use std::os::unix::io::{FromRawFd, RawFd};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
use thiserror::Error;
use vmm::config;
use vmm_sys_util::eventfd::EventFd;
@@ -151,8 +155,7 @@ fn create_app<'a>(
"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>",
affinity=<list_of_vcpus_with_their_associated_cpuset>",
)
.default_value(default_vcpus)
.group("vm-config"),
@@ -302,14 +305,6 @@ fn create_app<'a>(
.min_values(1)
.group("vm-config"),
)
.arg(
Arg::new("vdpa")
.long("vdpa")
.help(config::VdpaConfig::SYNTAX)
.takes_value(true)
.min_values(1)
.group("vm-config"),
)
.arg(
Arg::new("vsock")
.long("vsock")
@@ -500,21 +495,28 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
SeccompAction::Trap
};
// See https://github.com/rust-lang/libc/issues/716 why we can't get the details from siginfo_t
if seccomp_action == SeccompAction::Trap {
// SAFETY: We only using signal_hook for managing signals and only execute signal
// handler safe functions (writing to stderr) and manipulating signals.
unsafe {
signal_hook::low_level::register(signal_hook::consts::SIGSYS, || {
eprint!(
"\n==== Possible seccomp violation ====\n\
Try running with `strace -ff` to identify the cause and open an issue: \
https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new\n"
);
signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
thread::Builder::new()
.name("seccomp_signal_handler".to_string())
.spawn(move || {
for si in SignalsInfo::<WithRawSiginfo>::new(&[SIGSYS])
.unwrap()
.forever()
{
/* SYS_SECCOMP */
if si.si_code == 1 {
eprint!(
"\n==== seccomp violation ====\n\
Try running with `strace -ff` to identify the cause and open an issue: \
https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new\n"
);
signal_hook::low_level::emulate_default_handler(SIGSYS).unwrap();
}
}
})
}
.map_err(|e| eprintln!("Error adding SIGSYS signal handler: {}", e))
.ok();
.unwrap();
}
// Before we start any threads, mask the signals we'll be
@@ -632,8 +634,8 @@ mod unit_tests {
use crate::{create_app, prepare_default_values};
use std::path::PathBuf;
use vmm::config::{
CmdlineConfig, ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, KernelConfig,
MemoryConfig, RngConfig, VmConfig, VmParams,
CmdlineConfig, ConsoleConfig, ConsoleOutputMode, CpusConfig, KernelConfig, MemoryConfig,
RngConfig, VmConfig, VmParams,
};
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
@@ -680,7 +682,6 @@ mod unit_tests {
kvm_hyperv: false,
max_phys_bits: 46,
affinity: None,
features: CpuFeatures::default(),
},
memory: MemoryConfig {
size: 536_870_912,
@@ -722,7 +723,6 @@ mod unit_tests {
},
devices: None,
user_devices: None,
vdpa: None,
vsock: None,
iommu: false,
#[cfg(target_arch = "x86_64")]
@@ -1260,6 +1260,125 @@ mod unit_tests {
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,dax=on"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "dax": true}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=8589934592"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true", "--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 8589934592}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true","--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128, "cache_size": 4294967296}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor", "--kernel", "/path/to/kernel",
"--memory", "shared=true","--cpus", "boot=4",
"--fs",
"tag=virtiofs1,socket=/path/to/sock1,num_queues=4,queue_size=128,cache_size=4294967296"
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"memory" : { "shared": true, "size": 536870912 },
"cpus": {"boot_vcpus": 4, "max_vcpus": 4},
"fs": [
{"tag": "virtiofs1", "socket": "/path/to/sock1", "num_queues": 4, "queue_size": 128}
]
}"#,
false,
),
]
.iter()
.for_each(|(cli, openapi, equal)| {
@@ -1561,51 +1680,6 @@ mod unit_tests {
});
}
#[test]
fn test_valid_vm_config_vdpa() {
vec![
(
vec![
"cloud-hypervisor",
"--kernel",
"/path/to/kernel",
"--vdpa",
"path=/path/to/device/1",
"path=/path/to/device/2,num_queues=2",
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"vdpa": [
{"path": "/path/to/device/1", "num_queues": 1},
{"path": "/path/to/device/2", "num_queues": 2}
]
}"#,
true,
),
(
vec![
"cloud-hypervisor",
"--kernel",
"/path/to/kernel",
"--vdpa",
"path=/path/to/device/1",
"path=/path/to/device/2",
],
r#"{
"kernel": {"path": "/path/to/kernel"},
"vdpa": [
{"path": "/path/to/device/1"}
]
}"#,
false,
),
]
.iter()
.for_each(|(cli, openapi, equal)| {
compare_vm_config_cli_vs_json(cli, openapi, *equal);
});
}
#[test]
fn test_valid_vm_config_vsock() {
vec![

View File

@@ -2,13 +2,13 @@
name = "test_infra"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
dirs = "4.0.0"
epoll = "4.3.1"
lazy_static = "1.4.0"
libc = "0.2.123"
libc = "0.2.91"
ssh2 = { version = "0.9.1", features = ["vendored-openssl"]}
vmm-sys-util = "0.9.0"
wait-timeout = "0.2.0"

View File

@@ -8,7 +8,6 @@
// related warnings for our quality workflow to pass.
#![allow(dead_code)]
#[cfg(target_arch = "x86_64")]
#[macro_use]
extern crate lazy_static;
@@ -44,7 +43,6 @@ mod x86_64 {
pub const FOCAL_IMAGE_NAME_QCOW2: &str = "focal-server-cloudimg-amd64-custom-20210609-0.qcow2";
pub const FOCAL_IMAGE_NAME_VHD: &str = "focal-server-cloudimg-amd64-custom-20210609-0.vhd";
pub const FOCAL_IMAGE_NAME_VHDX: &str = "focal-server-cloudimg-amd64-custom-20210609-0.vhdx";
pub const JAMMY_IMAGE_NAME: &str = "jammy-server-cloudimg-amd64-custom-20220329-0.raw";
pub const WINDOWS_IMAGE_NAME: &str = "windows-server-2019.raw";
pub const OVMF_NAME: &str = "CLOUDHV.fd";
pub const GREP_SERIAL_IRQ_CMD: &str = "grep -c 'IO-APIC.*ttyS0' /proc/interrupts || true";
@@ -62,7 +60,6 @@ mod aarch64 {
pub const FOCAL_IMAGE_NAME_QCOW2: &str = "focal-server-cloudimg-arm64-custom-20210929-0.qcow2";
pub const FOCAL_IMAGE_NAME_VHD: &str = "focal-server-cloudimg-arm64-custom-20210929-0.vhd";
pub const FOCAL_IMAGE_NAME_VHDX: &str = "focal-server-cloudimg-arm64-custom-20210929-0.vhdx";
pub const JAMMY_IMAGE_NAME: &str = "jammy-server-cloudimg-arm64-custom-20220329-0.raw";
pub const GREP_SERIAL_IRQ_CMD: &str = "grep -c 'GICv3.*uart-pl011' /proc/interrupts || true";
pub const GREP_PMU_IRQ_CMD: &str = "grep -c 'GICv3.*arm-pmu' /proc/interrupts || true";
}
@@ -418,7 +415,7 @@ enum FwType {
RustHypervisorFirmware,
}
fn fw_path(_fw_type: FwType) -> String {
fn fw_path(fw_type: FwType) -> String {
let mut workload_path = dirs::home_dir().unwrap();
workload_path.push("workloads");
@@ -427,7 +424,7 @@ fn fw_path(_fw_type: FwType) -> String {
fw_path.push("CLOUDHV_EFI.fd");
#[cfg(target_arch = "x86_64")]
{
match _fw_type {
match fw_type {
FwType::Ovmf => fw_path.push(OVMF_NAME),
FwType::RustHypervisorFirmware => fw_path.push("hypervisor-fw"),
}
@@ -747,7 +744,7 @@ fn test_vhost_user_net(
);
// ACPI feature is needed.
#[cfg(target_arch = "x86_64")]
#[cfg(all(target_arch = "x86_64", feature = "acpi"))]
{
guest.enable_memory_hotplug();
@@ -886,7 +883,7 @@ fn test_vhost_user_blk(
);
// ACPI feature is needed.
#[cfg(target_arch = "x86_64")]
#[cfg(all(target_arch = "x86_64", feature = "acpi"))]
{
guest.enable_memory_hotplug();
@@ -1124,7 +1121,7 @@ fn test_virtio_fs(
);
// ACPI feature is needed.
#[cfg(target_arch = "x86_64")]
#[cfg(all(target_arch = "x86_64", feature = "acpi"))]
{
guest.enable_memory_hotplug();
@@ -1757,58 +1754,48 @@ mod parallel {
#[test]
#[cfg(target_arch = "x86_64")]
fn test_bionic_hypervisor_fw() {
test_simple_launch(fw_path(FwType::RustHypervisorFirmware), BIONIC_IMAGE_NAME)
}
fn test_simple_launch() {
let bionic = UbuntuDiskConfig::new(BIONIC_IMAGE_NAME.to_string());
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
#[test]
#[cfg(target_arch = "x86_64")]
fn test_focal_hypervisor_fw() {
test_simple_launch(fw_path(FwType::RustHypervisorFirmware), FOCAL_IMAGE_NAME)
}
vec![Box::new(bionic), Box::new(focal)]
.drain(..)
.for_each(|disk_config| {
vec![
fw_path(FwType::Ovmf),
fw_path(FwType::RustHypervisorFirmware),
]
.drain(..)
.for_each(|fw_path| {
let guest = Guest::new(disk_config.clone());
#[test]
#[cfg(target_arch = "x86_64")]
fn test_bionic_ovmf() {
test_simple_launch(fw_path(FwType::Ovmf), BIONIC_IMAGE_NAME)
}
let mut child = GuestCommand::new(&guest)
.args(&["--cpus", "boot=1"])
.args(&["--memory", "size=512M"])
.args(&["--kernel", fw_path.as_str()])
.default_disks()
.default_net()
.args(&["--serial", "tty", "--console", "off"])
.capture_output()
.spawn()
.unwrap();
#[test]
#[cfg(target_arch = "x86_64")]
fn test_focal_ovmf() {
test_simple_launch(fw_path(FwType::Ovmf), FOCAL_IMAGE_NAME)
}
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(Some(120)).unwrap();
#[cfg(target_arch = "x86_64")]
fn test_simple_launch(fw_path: String, disk_path: &str) {
let disk_config = Box::new(UbuntuDiskConfig::new(disk_path.to_string()));
let guest = Guest::new(disk_config);
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
});
let mut child = GuestCommand::new(&guest)
.args(&["--cpus", "boot=1"])
.args(&["--memory", "size=512M"])
.args(&["--kernel", fw_path.as_str()])
.default_disks()
.default_net()
.args(&["--serial", "tty", "--console", "off"])
.capture_output()
.spawn()
.unwrap();
let _ = child.kill();
let output = child.wait_with_output().unwrap();
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(Some(120)).unwrap();
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
assert!(guest.get_entropy().unwrap_or_default() >= 900);
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
handle_child_output(r, &output);
});
});
}
#[test]
@@ -2143,13 +2130,7 @@ mod parallel {
let (cmd_success, cmd_output) = remote_command_w_output(
&api_socket,
"add-disk",
Some(
format!(
"path={},id=test0,pci_segment=1,iommu=on",
test_disk_path.as_str()
)
.as_str(),
),
Some(format!("path={},id=test0,pci_segment=1", test_disk_path.as_str()).as_str()),
);
assert!(cmd_success);
assert!(String::from_utf8_lossy(&cmd_output)
@@ -2214,46 +2195,6 @@ mod parallel {
handle_child_output(r, &output);
}
#[test]
fn test_virtio_net_ctrl_queue() {
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let mut cmd = GuestCommand::new(&guest);
cmd.args(&["--cpus", "boot=1"])
.args(&["--memory", "size=512M"])
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.capture_output()
.default_disks()
.default_net();
let mut child = cmd.spawn().unwrap();
guest.wait_vm_boot(None).unwrap();
#[cfg(target_arch = "aarch64")]
let iface = "enp0s4";
#[cfg(target_arch = "x86_64")]
let iface = "ens4";
let r = std::panic::catch_unwind(|| {
assert_eq!(
guest
.ssh_command(
format!("sudo ethtool -K {} rx-gro-hw off && echo success", iface).as_str()
)
.unwrap()
.trim(),
"success"
);
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_pci_multiple_segments() {
@@ -2810,11 +2751,36 @@ mod parallel {
handle_child_output(r, &output);
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_fs_dax_on_default_cache_size() {
test_virtio_fs(true, None, "never", &prepare_virtiofsd, false, None)
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_fs_dax_on_cache_size_1_gib() {
test_virtio_fs(
true,
Some(0x4000_0000),
"never",
&prepare_virtiofsd,
false,
None,
)
}
#[test]
fn test_virtio_fs_dax_off() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, false, None)
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_fs_hotplug_dax_on() {
test_virtio_fs(true, None, "never", &prepare_virtiofsd, true, None)
}
#[test]
fn test_virtio_fs_hotplug_dax_off() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, true, None)
@@ -2823,13 +2789,27 @@ mod parallel {
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_fs_multi_segment_hotplug() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, true, Some(15))
test_virtio_fs(
true,
Some(0x4000_0000),
"never",
&prepare_virtiofsd,
true,
Some(15),
)
}
#[test]
#[cfg(not(feature = "mshv"))]
fn test_virtio_fs_multi_segment() {
test_virtio_fs(false, None, "never", &prepare_virtiofsd, false, Some(15))
test_virtio_fs(
true,
Some(0x4000_0000),
"never",
&prepare_virtiofsd,
false,
Some(15),
)
}
#[test]
@@ -3316,6 +3296,7 @@ mod parallel {
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
#[cfg(feature = "acpi")]
assert!(guest
.does_device_vendor_pair_match("0x1043", "0x1af4")
.unwrap_or_default());
@@ -4314,6 +4295,12 @@ mod parallel {
thread::sleep(std::time::Duration::new(20, 0));
let r = std::panic::catch_unwind(|| {
// On AArch64 when acpi is enabled, there is a 4 MiB gap between the RAM
// that the VMM gives and the guest can see.
// This is a temporary solution, will be fixed in future.
#[cfg(all(target_arch = "aarch64", feature = "acpi"))]
let guest_memory_size_kb = guest_memory_size_kb - 4 * 1024;
let overhead = get_vmm_overhead(child.id(), guest_memory_size_kb);
eprintln!(
"Guest memory overhead: {} vs {}",
@@ -5058,7 +5045,7 @@ mod parallel {
let guest = Guest::new(Box::new(focal));
let kernel_path = direct_kernel_boot_path();
let api_socket_source = format!("{}.1", temp_api_path(&guest.tmp_dir));
let api_socket = temp_api_path(&guest.tmp_dir);
let net_id = "net123";
let net_params = format!(
@@ -5074,7 +5061,7 @@ mod parallel {
let socket = temp_vsock_path(&guest.tmp_dir);
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket_source])
.args(&["--api-socket", &api_socket])
.args(&["--cpus", "boot=4"])
.args(&[
"--memory",
@@ -5110,11 +5097,11 @@ mod parallel {
// Check the guest RAM
assert!(guest.get_total_memory().unwrap_or_default() > 3_840_000);
// Increase guest RAM with virtio-mem
resize_command(&api_socket_source, None, Some(6 << 30), None);
resize_command(&api_socket, None, Some(6 << 30), None);
thread::sleep(std::time::Duration::new(5, 0));
assert!(guest.get_total_memory().unwrap_or_default() > 5_760_000);
// Use balloon to remove RAM from the VM
resize_command(&api_socket_source, None, None, Some(1 << 30));
resize_command(&api_socket, None, None, Some(1 << 30));
thread::sleep(std::time::Duration::new(5, 0));
let total_memory = guest.get_total_memory().unwrap_or_default();
assert!(total_memory > 4_800_000);
@@ -5131,16 +5118,12 @@ mod parallel {
// AArch64: Device hotplug is currently not supported, skipping here.
#[cfg(target_arch = "x86_64")]
{
assert!(remote_command(
&api_socket_source,
"remove-device",
Some(net_id),
));
assert!(remote_command(&api_socket, "remove-device", Some(net_id),));
thread::sleep(std::time::Duration::new(10, 0));
// Plug the virtio-net device again
assert!(remote_command(
&api_socket_source,
&api_socket,
"add-net",
Some(net_params.as_str()),
));
@@ -5148,11 +5131,11 @@ mod parallel {
}
// Pause the VM
assert!(remote_command(&api_socket_source, "pause", None));
assert!(remote_command(&api_socket, "pause", None));
// Take a snapshot from the VM
assert!(remote_command(
&api_socket_source,
&api_socket,
"snapshot",
Some(format!("file://{}", snapshot_dir).as_str()),
));
@@ -5179,11 +5162,9 @@ mod parallel {
.output()
.unwrap();
let api_socket_restored = format!("{}.2", temp_api_path(&guest.tmp_dir));
// Restore the VM from the snapshot
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket_restored])
.args(&["--api-socket", &api_socket])
.args(&[
"--restore",
format!("source_url=file://{}", snapshot_dir).as_str(),
@@ -5197,7 +5178,7 @@ mod parallel {
let r = std::panic::catch_unwind(|| {
// Resume the VM
assert!(remote_command(&api_socket_restored, "resume", None));
assert!(remote_command(&api_socket, "resume", None));
// Perform same checks to validate VM has been properly restored
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 4);
@@ -5205,11 +5186,11 @@ mod parallel {
assert!(total_memory > 4_800_000);
assert!(total_memory < 5_760_000);
// Deflate balloon to restore entire RAM to the VM
resize_command(&api_socket_restored, None, None, Some(0));
resize_command(&api_socket, None, None, Some(0));
thread::sleep(std::time::Duration::new(5, 0));
assert!(guest.get_total_memory().unwrap_or_default() > 5_760_000);
// Decrease guest RAM with virtio-mem
resize_command(&api_socket_restored, None, Some(5 << 30), None);
resize_command(&api_socket, None, Some(5 << 30), None);
thread::sleep(std::time::Duration::new(5, 0));
let total_memory = guest.get_total_memory().unwrap_or_default();
assert!(total_memory > 4_800_000);
@@ -5604,9 +5585,9 @@ mod parallel {
let focal2 = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest2 = Guest::new(Box::new(focal2));
let api_socket_source = format!("{}.1", temp_api_path(&guest2.tmp_dir));
let api_socket = temp_api_path(&guest2.tmp_dir);
let (mut child1, mut child2) = setup_ovs_dpdk_guests(&guest1, &guest2, &api_socket_source);
let (mut child1, mut child2) = setup_ovs_dpdk_guests(&guest1, &guest2, &api_socket);
// Create the snapshot directory
let snapshot_dir = temp_snapshot_dir_path(&guest2.tmp_dir);
@@ -5640,11 +5621,11 @@ mod parallel {
guest2.ssh_command("nc -vz 172.100.0.1 12345").unwrap();
// Pause the VM
assert!(remote_command(&api_socket_source, "pause", None));
assert!(remote_command(&api_socket, "pause", None));
// Take a snapshot from the VM
assert!(remote_command(
&api_socket_source,
&api_socket,
"snapshot",
Some(format!("file://{}", snapshot_dir).as_str()),
));
@@ -5665,10 +5646,9 @@ mod parallel {
.output()
.unwrap();
let api_socket_restored = format!("{}.2", temp_api_path(&guest2.tmp_dir));
// Restore the VM from the snapshot
let mut child2 = GuestCommand::new(&guest2)
.args(&["--api-socket", &api_socket_restored])
.args(&["--api-socket", &api_socket])
.args(&[
"--restore",
format!("source_url=file://{}", snapshot_dir).as_str(),
@@ -5682,7 +5662,7 @@ mod parallel {
let r = std::panic::catch_unwind(|| {
// Resume the VM
assert!(remote_command(&api_socket_restored, "resume", None));
assert!(remote_command(&api_socket, "resume", None));
// Spawn a new netcat listener in the first VM
let guest_ip = guest1.network.guest_ip.clone();
@@ -5768,11 +5748,16 @@ mod parallel {
exec_host_command_status("pkill -f nvmf_tgt");
}
#[ignore]
#[test]
#[cfg(target_arch = "aarch64")]
fn test_vfio_user() {
let jammy_image = JAMMY_IMAGE_NAME.to_string();
let jammy = UbuntuDiskConfig::new(jammy_image);
let guest = Guest::new(Box::new(jammy));
#[cfg(target_arch = "aarch64")]
let focal_image = FOCAL_IMAGE_UPDATE_KERNEL_NAME.to_string();
#[cfg(target_arch = "x86_64")]
let focal_image = FOCAL_IMAGE_NAME.to_string();
let focal = UbuntuDiskConfig::new(focal_image);
let guest = Guest::new(Box::new(focal));
let spdk_nvme_dir = guest.tmp_dir.as_path().join("test-vfio-user");
setup_spdk_nvme(spdk_nvme_dir.as_path());
@@ -5781,9 +5766,8 @@ mod parallel {
let mut child = GuestCommand::new(&guest)
.args(&["--api-socket", &api_socket])
.args(&["--cpus", "boot=1"])
.args(&["--memory", "size=512M,shared=on,hugepages=on"])
.args(&["--memory", "size=512M,shared=on"])
.args(&["--kernel", fw_path(FwType::RustHypervisorFirmware).as_str()])
.args(&["--serial", "tty", "--console", "off"])
.default_disks()
.default_net()
.capture_output()
@@ -5808,9 +5792,9 @@ mod parallel {
);
assert!(cmd_success);
assert!(String::from_utf8_lossy(&cmd_output)
.contains("{\"id\":\"vfio_user0\",\"bdf\":\"0000:00:05.0\"}"));
.contains("{\"id\":\"vfio_user0\",\"bdf\":\"0000:00:06.0\"}"));
thread::sleep(std::time::Duration::new(10, 0));
thread::sleep(std::time::Duration::new(1, 0));
// Check both if /dev/nvme exists and if the block size is 128M.
assert_eq!(
@@ -5853,207 +5837,6 @@ mod parallel {
handle_child_output(r, &output);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_vdpa_block() {
// Before trying to run the test, verify the vdpa_sim_blk module is correctly loaded.
if !exec_host_command_status("lsmod | grep vdpa_sim_blk").success() {
return;
}
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let api_socket = temp_api_path(&guest.tmp_dir);
let kernel_path = direct_kernel_boot_path();
let mut child = GuestCommand::new(&guest)
.args(&["--cpus", "boot=2"])
.args(&["--memory", "size=512M,hugepages=on"])
.args(&["--kernel", kernel_path.to_str().unwrap()])
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.default_disks()
.default_net()
.args(&["--vdpa", "path=/dev/vhost-vdpa-0,num_queues=1"])
.args(&["--platform", "num_pci_segments=2,iommu_segments=1"])
.args(&["--api-socket", &api_socket])
.capture_output()
.spawn()
.unwrap();
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
// Check both if /dev/vdc exists and if the block size is 128M.
assert_eq!(
guest
.ssh_command("lsblk | grep vdc | grep -c 128M")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or_default(),
1
);
// Check the content of the block device after we wrote to it.
// The vpda-sim-blk should let us read what we previously wrote.
guest
.ssh_command("sudo bash -c 'echo foobar > /dev/vdc'")
.unwrap();
assert_eq!(
guest.ssh_command("sudo head -1 /dev/vdc").unwrap().trim(),
"foobar"
);
// Hotplug an extra vDPA block device behind the vIOMMU
// Add a new vDPA device to the VM
let (cmd_success, cmd_output) = remote_command_w_output(
&api_socket,
"add-vdpa",
Some("id=myvdpa0,path=/dev/vhost-vdpa-1,num_queues=1,pci_segment=1,iommu=on"),
);
assert!(cmd_success);
assert!(String::from_utf8_lossy(&cmd_output)
.contains("{\"id\":\"myvdpa0\",\"bdf\":\"0001:00:01.0\"}"));
thread::sleep(std::time::Duration::new(10, 0));
// Check IOMMU setup
assert!(guest
.does_device_vendor_pair_match("0x1057", "0x1af4")
.unwrap_or_default());
assert_eq!(
guest
.ssh_command("ls /sys/kernel/iommu_groups/0/devices")
.unwrap()
.trim(),
"0001:00:01.0"
);
// Check both if /dev/vdd exists and if the block size is 128M.
assert_eq!(
guest
.ssh_command("lsblk | grep vdd | grep -c 128M")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or_default(),
1
);
// Write some content to the block device we've just plugged.
guest
.ssh_command("sudo bash -c 'echo foobar > /dev/vdd'")
.unwrap();
// Check we can read the content back.
assert_eq!(
guest.ssh_command("sudo head -1 /dev/vdd").unwrap().trim(),
"foobar"
);
// Unplug the device
let cmd_success = remote_command(&api_socket, "remove-device", Some("myvdpa0"));
assert!(cmd_success);
thread::sleep(std::time::Duration::new(10, 0));
// Check /dev/vdd doesn't exist anymore
assert_eq!(
guest
.ssh_command("lsblk | grep -c vdd || true")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or(1),
0
);
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
#[test]
#[cfg(target_arch = "x86_64")]
fn test_vdpa_net() {
// Before trying to run the test, verify the vdpa_sim_net module is correctly loaded.
if !exec_host_command_status("lsmod | grep vdpa_sim_net").success() {
return;
}
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
let guest = Guest::new(Box::new(focal));
let kernel_path = direct_kernel_boot_path();
let mut child = GuestCommand::new(&guest)
.args(&["--cpus", "boot=2"])
.args(&["--memory", "size=512M,hugepages=on"])
.args(&["--kernel", kernel_path.to_str().unwrap()])
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
.default_disks()
.default_net()
.args(&["--vdpa", "path=/dev/vhost-vdpa-2,num_queues=2"])
.capture_output()
.spawn()
.unwrap();
let r = std::panic::catch_unwind(|| {
guest.wait_vm_boot(None).unwrap();
// Check we can find network interface related to vDPA device
assert_eq!(
guest
.ssh_command("ip -o link | grep -c ens6")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or(0),
1
);
guest
.ssh_command("sudo ip addr add 172.16.1.2/24 dev ens6")
.unwrap();
guest.ssh_command("sudo ip link set up dev ens6").unwrap();
// Check there is no packet yet on both TX/RX of the network interface
assert_eq!(
guest
.ssh_command("ip -j -p -s link show ens6 | grep -c '\"packets\": 0'")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or(0),
2
);
// Send 6 packets with ping command
guest.ssh_command("ping 172.16.1.10 -c 6 || true").unwrap();
// Check we can find 6 packets on both TX/RX of the network interface
assert_eq!(
guest
.ssh_command("ip -j -p -s link show ens6 | grep -c '\"packets\": 6'")
.unwrap()
.trim()
.parse::<u32>()
.unwrap_or(0),
2
);
// No need to check for hotplug as we already tested it through
// test_vdpa_block()
});
let _ = child.kill();
let output = child.wait_with_output().unwrap();
handle_child_output(r, &output);
}
}
mod sequential {
@@ -6484,10 +6267,10 @@ mod windows {
ovmf_path.push(OVMF_NAME);
let tmp_dir = TempDir::new_with_prefix("/tmp/ch").unwrap();
let api_socket_source = format!("{}.1", temp_api_path(&tmp_dir));
let api_socket = temp_api_path(&tmp_dir);
let mut child = GuestCommand::new(windows_guest.guest())
.args(&["--api-socket", &api_socket_source])
.args(&["--api-socket", &api_socket])
.args(&["--cpus", "boot=2,kvm_hyperv=on"])
.args(&["--memory", "size=4G"])
.args(&["--kernel", ovmf_path.to_str().unwrap()])
@@ -6514,11 +6297,11 @@ mod windows {
let snapshot_dir = temp_snapshot_dir_path(&tmp_dir);
// Pause the VM
assert!(remote_command(&api_socket_source, "pause", None));
assert!(remote_command(&api_socket, "pause", None));
// Take a snapshot from the VM
assert!(remote_command(
&api_socket_source,
&api_socket,
"snapshot",
Some(format!("file://{}", snapshot_dir).as_str()),
));
@@ -6529,11 +6312,9 @@ mod windows {
let _ = child.kill();
child.wait().unwrap();
let api_socket_restored = format!("{}.2", temp_api_path(&tmp_dir));
// Restore the VM from the snapshot
let mut child = GuestCommand::new(windows_guest.guest())
.args(&["--api-socket", &api_socket_restored])
.args(&["--api-socket", &api_socket])
.args(&[
"--restore",
format!("source_url=file://{}", snapshot_dir).as_str(),
@@ -6547,7 +6328,7 @@ mod windows {
let r = std::panic::catch_unwind(|| {
// Resume the VM
assert!(remote_command(&api_socket_restored, "resume", None));
assert!(remote_command(&api_socket, "resume", None));
windows_guest.shutdown();
});
@@ -7289,7 +7070,7 @@ mod live_migration {
"--memory-zone",
"id=mem0,size=1G,hotplug_size=32G",
"id=mem1,size=1G,hotplug_size=32G",
"id=mem2,size=2G,hotplug_size=32G",
"id=mem2,size=1G,hotplug_size=32G",
"--numa",
"guest_numa_id=0,cpus=[0-2,9],distances=[1@15,2@20],memory_zones=mem0",
"guest_numa_id=1,cpus=[3-4,6-8],distances=[0@20,2@25],memory_zones=mem1",
@@ -7340,7 +7121,7 @@ mod live_migration {
// virtio-mem regions being used.
if numa {
guest.check_numa_common(
Some(&[960_000, 960_000, 1_920_000]),
Some(&[960_000, 960_000, 960_000]),
Some(&[vec![0, 1, 2], vec![3, 4], vec![5]]),
Some(&["10 15 20", "20 10 25", "25 30 10"]),
);
@@ -7355,7 +7136,7 @@ mod live_migration {
// has been assigned the right amount of memory.
resize_zone_command(&src_api_socket, "mem0", "2G");
resize_zone_command(&src_api_socket, "mem1", "2G");
resize_zone_command(&src_api_socket, "mem2", "3G");
resize_zone_command(&src_api_socket, "mem2", "2G");
thread::sleep(std::time::Duration::new(5, 0));
guest.check_numa_common(Some(&[1_920_000, 1_920_000, 1_920_000]), None, None);
@@ -7511,15 +7292,14 @@ mod live_migration {
let r = std::panic::catch_unwind(|| {
// Perform same checks to validate VM has been properly migrated
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 6);
#[cfg(target_arch = "x86_64")]
if numa {
assert!(guest.get_total_memory().unwrap_or_default() > 6_720_000);
#[cfg(target_arch = "x86_64")]
assert!(guest.get_total_memory().unwrap_or_default() > 5_760_000);
#[cfg(target_arch = "aarch64")]
assert!(guest.get_total_memory().unwrap_or_default() > 2_880_000);
} else {
assert!(guest.get_total_memory().unwrap_or_default() > 3_840_000);
}
#[cfg(target_arch = "aarch64")]
assert!(guest.get_total_memory().unwrap_or_default() > 3_840_000);
guest.check_devices_common(None, Some(&console_text));
// Perform NUMA related checks
@@ -7527,7 +7307,7 @@ mod live_migration {
#[cfg(target_arch = "aarch64")]
{
guest.check_numa_common(
Some(&[960_000, 960_000, 1_920_000]),
Some(&[960_000, 960_000, 960_000]),
Some(&[vec![0, 1, 2], vec![3, 4], vec![5]]),
Some(&["10 15 20", "20 10 25", "25 30 10"]),
);
@@ -7538,7 +7318,7 @@ mod live_migration {
#[cfg(target_arch = "x86_64")]
{
guest.check_numa_common(
Some(&[1_920_000, 1_920_000, 2_880_000]),
Some(&[1_920_000, 1_920_000, 1_920_000]),
Some(&[vec![0, 1, 2], vec![3, 4], vec![5]]),
Some(&["10 15 20", "20 10 25", "25 30 10"]),
);
@@ -7807,7 +7587,7 @@ mod live_migration {
}
}
#[cfg(target_arch = "aarch64")]
#[cfg(all(target_arch = "aarch64", feature = "acpi"))]
mod aarch64_acpi {
use crate::*;
@@ -7870,9 +7650,7 @@ mod aarch64_acpi {
_test_power_button(true);
}
// https://github.com/cloud-hypervisor/cloud-hypervisor/issues/3941
#[test]
#[ignore]
fn test_virtio_iommu() {
_test_virtio_iommu(true)
}

View File

@@ -2,12 +2,12 @@
name = "vfio_user"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
anyhow = "1.0.56"
libc = "0.2.123"
log = "0.4.16"
anyhow = "1.0.55"
libc = "0.2.119"
log = "0.4.14"
serde = {version = ">=1.0.27", features = ["rc"] }
serde_derive = ">=1.0.27"
serde_json = ">=1.0.9"

View File

@@ -255,8 +255,6 @@ pub enum Error {
StreamWrite(#[source] std::io::Error),
#[error("Error reading from stream: {0}")]
StreamRead(#[source] std::io::Error),
#[error("Error shutting down stream: {0}")]
StreamShutdown(#[source] std::io::Error),
#[error("Error writing with file descriptors: {0}")]
SendWithFd(#[source] vmm_sys_util::errno::Error),
#[error("Error reading with file descriptors: {0}")]
@@ -667,10 +665,4 @@ impl Client {
pub fn resettable(&self) -> bool {
self.resettable
}
pub fn shutdown(&self) -> Result<(), Error> {
self.stream
.shutdown(std::net::Shutdown::Both)
.map_err(Error::StreamShutdown)
}
}

View File

@@ -2,14 +2,14 @@
name = "vhdx"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
license = "Apache-2.0"
[dependencies]
byteorder = "1.4.3"
crc32c = "0.6.3"
libc = "0.2.123"
log = "0.4.16"
crc32c = "0.6.1"
libc = "0.2.119"
log = "0.4.14"
remain = "0.2.2"
thiserror = "1.0"
uuid = { version = "0.8.2", features = ["v4"] }

View File

@@ -2,22 +2,19 @@
name = "vhost_user_block"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
block_util = { path = "../block_util" }
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
clap = { version = "3.1.5", features = ["wrap_help"] }
env_logger = "0.9.0"
epoll = "4.3.1"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
option_parser = { path = "../option_parser" }
qcow = { path = "../qcow" }
vhost = { version = "0.4.0", features = ["vhost-user-slave"] }
vhost-user-backend = "0.3.0"
vhost = { version = "0.3.0", features = ["vhost-user-slave"] }
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost-user-backend", branch = "main" }
virtio-bindings = "0.1.0"
vm-memory = "0.7.0"
vmm-sys-util = "0.9.0"
[build-dependencies]
clap = { version = "3.1.8", features = ["cargo"] }

View File

@@ -2,21 +2,18 @@
name = "vhost_user_net"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[dependencies]
clap = { version = "3.1.8", features = ["wrap_help","cargo"] }
clap = { version = "3.1.5", features = ["wrap_help"] }
env_logger = "0.9.0"
epoll = "4.3.1"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
net_util = { path = "../net_util" }
option_parser = { path = "../option_parser" }
vhost = { version = "0.4.0", features = ["vhost-user-slave"] }
vhost-user-backend = "0.3.0"
vhost = { version = "0.3.0", features = ["vhost-user-slave"] }
vhost-user-backend = { git = "https://github.com/rust-vmm/vhost-user-backend", branch = "main" }
virtio-bindings = "0.1.0"
vm-memory = "0.7.0"
vmm-sys-util = "0.9.0"
[build-dependencies]
clap = { version = "3.1.8", features = ["cargo"] }

View File

@@ -2,22 +2,22 @@
name = "virtio-devices"
version = "0.1.0"
authors = ["The Cloud Hypervisor Authors"]
edition = "2021"
edition = "2018"
[features]
default = []
mshv = []
[dependencies]
anyhow = "1.0.56"
anyhow = "1.0.55"
arc-swap = "1.5.0"
block_util = { path = "../block_util" }
byteorder = "1.4.3"
epoll = "4.3.1"
event_monitor = { path = "../event_monitor" }
io-uring = "0.5.2"
libc = "0.2.123"
log = "0.4.16"
libc = "0.2.119"
log = "0.4.14"
net_gen = { path = "../net_gen" }
net_util = { path = "../net_util" }
pci = { path = "../pci" }
@@ -26,12 +26,11 @@ seccompiler = "0.2.0"
serde = "1.0.136"
serde_derive = "1.0.136"
serde_json = "1.0.79"
thiserror = "1.0.30"
versionize = "0.1.6"
versionize_derive = "0.1.4"
vhost = { version = "0.4.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
vhost = { version = "0.3.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern"] }
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
virtio-queue = "0.2.0"
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
vm-allocator = { path = "../vm-allocator" }
vm-device = { path = "../vm-device" }
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }

View File

@@ -151,7 +151,7 @@ impl ConsoleEpollHandler {
if let Err(e) = desc_chain.memory().write_slice(
&source_slice[..],
desc.addr()
.translate_gva(self.access_platform.as_ref(), desc.len() as usize),
.translate(self.access_platform.as_ref(), desc.len() as usize),
) {
error!("Failed to write slice: {:?}", e);
avail_iter.go_to_previous_position();
@@ -190,7 +190,7 @@ impl ConsoleEpollHandler {
if let Some(ref mut out) = self.endpoint.out_file() {
let _ = desc_chain.memory().write_to(
desc.addr()
.translate_gva(self.access_platform.as_ref(), desc.len() as usize),
.translate(self.access_platform.as_ref(), desc.len() as usize),
out,
desc.len() as usize,
);

View File

@@ -207,10 +207,7 @@ pub trait VirtioDevice: Send {
/// On the other side, the implementation itself should be provided by the code
/// emulating the IOMMU for the guest.
pub trait DmaRemapping: Send + Sync {
/// Provide a way to translate GVA address ranges into GPAs.
fn translate_gva(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error>;
/// Provide a way to translate GPA address ranges into GVAs.
fn translate_gpa(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error>;
fn translate(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error>;
}
/// Structure to handle device state common to all devices

View File

@@ -20,7 +20,7 @@ use std::ops::Bound::Included;
use std::os::unix::io::AsRawFd;
use std::result;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Barrier, Mutex, RwLock};
use std::sync::{Arc, Barrier, RwLock};
use versionize::{VersionMap, Versionize, VersionizeResult};
use versionize_derive::Versionize;
use virtio_queue::{DescriptorChain, Queue};
@@ -572,7 +572,7 @@ struct IommuEpollHandler {
kill_evt: EventFd,
pause_evt: EventFd,
mapping: Arc<IommuMapping>,
ext_mapping: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
ext_domain_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
msi_iova_space: (u64, u64),
}
@@ -585,7 +585,7 @@ impl IommuEpollHandler {
let len = match Request::parse(
&mut desc_chain,
&self.mapping,
&self.ext_mapping.lock().unwrap(),
&self.ext_mapping,
&mut self.ext_domain_mapping,
self.msi_iova_space,
) {
@@ -683,8 +683,8 @@ pub struct IommuMapping {
}
impl DmaRemapping for IommuMapping {
fn translate_gva(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error> {
debug!("Translate GVA addr 0x{:x}", addr);
fn translate(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error> {
debug!("Translate addr 0x{:x}", addr);
if let Some(domain) = self.endpoints.read().unwrap().get(&id) {
if let Some(mapping) = self.mappings.read().unwrap().get(domain) {
let range_start = if VIRTIO_IOMMU_PAGE_SIZE_MASK > addr {
@@ -695,37 +695,15 @@ impl DmaRemapping for IommuMapping {
for (&key, &value) in mapping.range((Included(&range_start), Included(&addr))) {
if addr >= key && addr < key + value.size {
let new_addr = addr - key + value.gpa;
debug!("Into GPA addr 0x{:x}", new_addr);
debug!("Into new_addr 0x{:x}", new_addr);
return Ok(new_addr);
}
}
}
}
Err(io::Error::new(
io::ErrorKind::Other,
format!("failed to translate GVA addr 0x{:x}", addr),
))
}
fn translate_gpa(&self, id: u32, addr: u64) -> std::result::Result<u64, std::io::Error> {
debug!("Translate GPA addr 0x{:x}", addr);
if let Some(domain) = self.endpoints.read().unwrap().get(&id) {
if let Some(mapping) = self.mappings.read().unwrap().get(domain) {
for (&key, &value) in mapping.iter() {
if addr >= value.gpa && addr < value.gpa + value.size {
let new_addr = addr - value.gpa + key;
debug!("Into GVA addr 0x{:x}", new_addr);
return Ok(new_addr);
}
}
}
}
Err(io::Error::new(
io::ErrorKind::Other,
format!("failed to translate GPA addr 0x{:x}", addr),
))
debug!("Into same addr...");
Ok(addr)
}
}
@@ -742,11 +720,8 @@ impl AccessPlatformMapping {
}
impl AccessPlatform for AccessPlatformMapping {
fn translate_gva(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
self.mapping.translate_gva(self.id, base)
}
fn translate_gpa(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
self.mapping.translate_gpa(self.id, base)
fn translate(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
self.mapping.translate(self.id, base)
}
}
@@ -755,7 +730,7 @@ pub struct Iommu {
id: String,
config: VirtioIommuConfig,
mapping: Arc<IommuMapping>,
ext_mapping: Arc<Mutex<BTreeMap<u32, Arc<dyn ExternalDmaMapping>>>>,
ext_mapping: BTreeMap<u32, Arc<dyn ExternalDmaMapping>>,
seccomp_action: SeccompAction,
exit_evt: EventFd,
msi_iova_space: (u64, u64),
@@ -803,7 +778,7 @@ impl Iommu {
},
config,
mapping: mapping.clone(),
ext_mapping: Arc::new(Mutex::new(BTreeMap::new())),
ext_mapping: BTreeMap::new(),
seccomp_action,
exit_evt,
msi_iova_space,
@@ -849,7 +824,7 @@ impl Iommu {
}
pub fn add_external_mapping(&mut self, device_id: u32, mapping: Arc<dyn ExternalDmaMapping>) {
self.ext_mapping.lock().unwrap().insert(device_id, mapping);
self.ext_mapping.insert(device_id, mapping);
}
}

View File

@@ -34,7 +34,6 @@ mod rng;
pub mod seccomp_filters;
mod thread_helper;
pub mod transport;
pub mod vdpa;
pub mod vhost_user;
pub mod vsock;
pub mod watchdog;
@@ -49,7 +48,6 @@ pub use self::mem::*;
pub use self::net::*;
pub use self::pmem::*;
pub use self::rng::*;
pub use self::vdpa::*;
pub use self::vsock::*;
pub use self::watchdog::*;
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory};
@@ -102,8 +100,6 @@ pub enum ActivateError {
CreateSeccompFilter(seccompiler::Error),
/// Cannot create rate limiter
CreateRateLimiter(std::io::Error),
/// Failed activating the vDPA device
ActivateVdpa(vdpa::Error),
}
pub type ActivateResult = std::result::Result<(), ActivateError>;
@@ -114,7 +110,6 @@ pub type DeviceEventT = u16;
pub enum Error {
FailedSignalingUsedQueue(io::Error),
IoError(io::Error),
VdpaUpdateMemory(vdpa::Error),
VhostUserUpdateMemory(vhost_user::Error),
VhostUserAddMemoryRegion(vhost_user::Error),
SetShmRegionsNotSupported,

View File

@@ -137,8 +137,6 @@ pub enum Error {
DmaUnmap(std::io::Error),
// Invalid DMA mapping handler
InvalidDmaMappingHandler,
// Not activated by the guest
NotActivatedByGuest,
}
#[repr(C)]
@@ -329,7 +327,6 @@ impl Request {
pub struct ResizeSender {
hotplugged_size: Arc<AtomicU64>,
activated: Arc<AtomicBool>,
tx: mpsc::Sender<Result<(), Error>>,
evt: EventFd,
}
@@ -348,7 +345,6 @@ impl Clone for ResizeSender {
fn clone(&self) -> Self {
ResizeSender {
hotplugged_size: self.hotplugged_size.clone(),
activated: self.activated.clone(),
tx: self.tx.clone(),
evt: self
.evt
@@ -360,7 +356,6 @@ impl Clone for ResizeSender {
pub struct Resize {
hotplugged_size: Arc<AtomicU64>,
activated: Arc<AtomicBool>,
tx: mpsc::Sender<Result<(), Error>>,
rx: mpsc::Receiver<Result<(), Error>>,
evt: EventFd,
@@ -372,7 +367,6 @@ impl Resize {
Ok(Resize {
hotplugged_size: Arc::new(AtomicU64::new(hotplugged_size)),
activated: Arc::new(AtomicBool::default()),
tx,
rx,
evt: EventFd::new(EFD_NONBLOCK)?,
@@ -382,17 +376,12 @@ impl Resize {
pub fn new_resize_sender(&self) -> Result<ResizeSender, Error> {
Ok(ResizeSender {
hotplugged_size: self.hotplugged_size.clone(),
activated: self.activated.clone(),
tx: self.tx.clone(),
evt: self.evt.try_clone().map_err(Error::EventFdTryCloneFail)?,
})
}
pub fn work(&self, desired_size: u64) -> Result<(), Error> {
if !self.activated.load(Ordering::Acquire) {
return Err(Error::NotActivatedByGuest);
}
self.hotplugged_size.store(desired_size, Ordering::Release);
self.evt.write(1).map_err(Error::EventFdWriteFail)?;
self.rx.recv().map_err(Error::MpscRecvFail)?
@@ -1057,14 +1046,11 @@ impl VirtioDevice for Mem {
)?;
self.common.epoll_threads = Some(epoll_threads);
self.resize.activated.store(true, Ordering::Release);
event!("virtio-device", "activated", "id", &self.id);
Ok(())
}
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
self.resize.activated.store(false, Ordering::Release);
let result = self.common.reset();
event!("virtio-device", "reset", "id", &self.id);
result

View File

@@ -53,20 +53,9 @@ pub struct NetCtrlEpollHandler {
pub queue_evt: EventFd,
pub queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
pub access_platform: Option<Arc<dyn AccessPlatform>>,
pub interrupt_cb: Arc<dyn VirtioInterrupt>,
pub queue_index: u16,
}
impl NetCtrlEpollHandler {
fn signal_used_queue(&self, queue_index: u16) -> result::Result<(), DeviceError> {
self.interrupt_cb
.trigger(VirtioInterruptType::Queue(queue_index))
.map_err(|e| {
error!("Failed to signal used queue: {:?}", e);
DeviceError::FailedSignalingUsedQueue(e)
})
}
pub fn run_ctrl(
&mut self,
paused: Arc<AtomicBool>,
@@ -86,33 +75,19 @@ impl EpollHelperHandler for NetCtrlEpollHandler {
match ev_type {
CTRL_QUEUE_EVENT => {
if let Err(e) = self.queue_evt.read() {
error!("Failed to get control queue event: {:?}", e);
error!("failed to get ctl queue event: {:?}", e);
return true;
}
if let Err(e) = self
.ctrl_q
.process(&mut self.queue, self.access_platform.as_ref())
{
error!("Failed to process control queue: {:?}", e);
error!("failed to process ctrl queue: {:?}", e);
return true;
} else {
match self.queue.needs_notification() {
Ok(true) => {
if let Err(e) = self.signal_used_queue(self.queue_index) {
error!("Error signalling that control queue was used: {:?}", e);
return true;
}
}
Ok(false) => {}
Err(e) => {
error!("Error getting notification state of control queue: {}", e);
return true;
}
}
}
}
_ => {
error!("Unknown event for virtio-net control queue");
error!("Unknown event for virtio-net");
return true;
}
}
@@ -590,25 +565,22 @@ impl VirtioDevice for Net {
) -> ActivateResult {
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
let num_queues = queues.len();
let queue_num = queues.len();
let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 {
let ctrl_queue_index = num_queues - 1;
let mut ctrl_queue = queues.remove(ctrl_queue_index);
let ctrl_queue_evt = queue_evts.remove(ctrl_queue_index);
if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && queue_num % 2 != 0 {
let mut cvq_queue = queues.remove(queue_num - 1);
let cvq_queue_evt = queue_evts.remove(queue_num - 1);
ctrl_queue.set_event_idx(event_idx);
cvq_queue.set_event_idx(event_idx);
let (kill_evt, pause_evt) = self.common.dup_eventfds();
let mut ctrl_handler = NetCtrlEpollHandler {
kill_evt,
pause_evt,
ctrl_q: CtrlQueue::new(self.taps.clone()),
queue: ctrl_queue,
queue_evt: ctrl_queue_evt,
queue: cvq_queue,
queue_evt: cvq_queue_evt,
access_platform: self.common.access_platform.clone(),
queue_index: ctrl_queue_index as u16,
interrupt_cb: interrupt_cb.clone(),
};
let paused = self.common.paused.clone();

View File

@@ -133,10 +133,7 @@ impl Request {
let request: VirtioPmemReq = desc_chain
.memory()
.read_obj(
desc.addr()
.translate_gva(access_platform, desc.len() as usize),
)
.read_obj(desc.addr().translate(access_platform, desc.len() as usize))
.map_err(Error::GuestMemory)?;
let request_type = match request.type_ {
@@ -159,7 +156,7 @@ impl Request {
type_: request_type,
status_addr: status_desc
.addr()
.translate_gva(access_platform, status_desc.len() as usize),
.translate(access_platform, status_desc.len() as usize),
})
}
}

View File

@@ -61,7 +61,7 @@ impl RngEpollHandler {
.memory()
.read_from(
desc.addr()
.translate_gva(self.access_platform.as_ref(), desc.len() as usize),
.translate(self.access_platform.as_ref(), desc.len() as usize),
&mut self.random_file,
desc.len() as usize,
)

View File

@@ -160,8 +160,6 @@ fn virtio_vhost_fs_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_connect, vec![]),
(libc::SYS_nanosleep, vec![]),
(libc::SYS_pread64, vec![]),
(libc::SYS_pwrite64, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
@@ -180,6 +178,7 @@ fn virtio_vhost_net_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
(libc::SYS_getcwd, vec![]),
(libc::SYS_listen, vec![]),
(libc::SYS_recvmsg, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_sendmsg, vec![]),
(libc::SYS_sendto, vec![]),
(libc::SYS_socket, vec![]),
@@ -243,6 +242,7 @@ fn get_seccomp_rules(thread_type: Thread) -> Vec<(i64, Vec<SeccompRule>)> {
fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
vec![
(libc::SYS_brk, vec![]),
#[cfg(feature = "mshv")]
(libc::SYS_clock_gettime, vec![]),
(libc::SYS_close, vec![]),
(libc::SYS_dup, vec![]),
@@ -259,7 +259,6 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
(libc::SYS_openat, vec![]),
(libc::SYS_read, vec![]),
(libc::SYS_rt_sigprocmask, vec![]),
(libc::SYS_rt_sigreturn, vec![]),
(libc::SYS_sigaltstack, vec![]),
(libc::SYS_write, vec![]),
]

View File

@@ -204,15 +204,11 @@ impl VirtioPciCommonConfig {
// Translate address of descriptor table and vrings.
if let Some(access_platform) = &self.access_platform {
if ready {
let desc_table = access_platform
.translate_gva(q.state.desc_table.0, 0)
.unwrap();
let avail_ring = access_platform
.translate_gva(q.state.avail_ring.0, 0)
.unwrap();
let used_ring = access_platform
.translate_gva(q.state.used_ring.0, 0)
.unwrap();
let desc_table =
access_platform.translate(q.state.desc_table.0, 0).unwrap();
let avail_ring =
access_platform.translate(q.state.avail_ring.0, 0).unwrap();
let used_ring = access_platform.translate(q.state.used_ring.0, 0).unwrap();
q.set_desc_table_address(
Some((desc_table & 0xffff_ffff) as u32),
Some((desc_table >> 32) as u32),

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