mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
260 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef4fbf086f | ||
|
|
9f8aeacd3d | ||
|
|
c9f94be7ab | ||
|
|
af49b10cf2 | ||
|
|
2fc2cabcbc | ||
|
|
ce7db3f7c3 | ||
|
|
bcdd23956f | ||
|
|
b1f3860d9a | ||
|
|
341152b4c7 | ||
|
|
e013fdd9d4 | ||
|
|
eee31f1d41 | ||
|
|
d0be450b1b | ||
|
|
3a683b54d5 | ||
|
|
af4a193b43 | ||
|
|
2b2d00653c | ||
|
|
318caeb9d8 | ||
|
|
612a8dfb1b | ||
|
|
321d6f47e6 | ||
|
|
035c4b20fb | ||
|
|
ee0cf3a715 | ||
|
|
ffef4ae5ac | ||
|
|
8f98240ed4 | ||
|
|
5b0de115f0 | ||
|
|
308b74f3a4 | ||
|
|
441b58437f | ||
|
|
829d310c57 | ||
|
|
9c7ee4ab3d | ||
|
|
ab5a731160 | ||
|
|
f0c1f8d079 | ||
|
|
56dbb8f0db | ||
|
|
66f8841ba1 | ||
|
|
5641e3a283 | ||
|
|
653d0548eb | ||
|
|
50241f94d9 | ||
|
|
7633d47293 | ||
|
|
939cc348ed | ||
|
|
744f2b011b | ||
|
|
08120b79fc | ||
|
|
9b0b881351 | ||
|
|
c1f4a7b295 | ||
|
|
36890373cd | ||
|
|
107f4bdc12 | ||
|
|
8899ebd63c | ||
|
|
c19c73cb99 | ||
|
|
4e0dc5203a | ||
|
|
61afd93a50 | ||
|
|
9dfc39d336 | ||
|
|
e70bf59809 | ||
|
|
d516374c39 | ||
|
|
9b84c6c3f5 | ||
|
|
9b54a8fb1c | ||
|
|
dd13fee3d7 | ||
|
|
3042a0baf3 | ||
|
|
dbda3ade92 | ||
|
|
6dc7e21327 | ||
|
|
166111a0d8 | ||
|
|
73bfaace83 | ||
|
|
95cd81073e | ||
|
|
3603c51f0b | ||
|
|
8c172e41c6 | ||
|
|
5ec47d4883 | ||
|
|
1617736937 | ||
|
|
a9340f5d9d | ||
|
|
82cac6f6ad | ||
|
|
c1206b604e | ||
|
|
0a32779506 | ||
|
|
4625f3ca3a | ||
|
|
3945253619 | ||
|
|
a5296a8147 | ||
|
|
7acfff5da7 | ||
|
|
026d8908fd | ||
|
|
c8ad2bfc05 | ||
|
|
e50a641126 | ||
|
|
8f90fba250 | ||
|
|
3ce0fef7fd | ||
|
|
6cb1d908bf | ||
|
|
51ebc3ac92 | ||
|
|
5368ff28da | ||
|
|
3993663e5c | ||
|
|
2c9cf8d8af | ||
|
|
b4eb2af1c6 | ||
|
|
7674196113 | ||
|
|
c71cb00a5a | ||
|
|
895dc12a74 | ||
|
|
9cb996db09 | ||
|
|
90245be978 | ||
|
|
15e2218c25 | ||
|
|
e33279471f | ||
|
|
993a8324e2 | ||
|
|
76dbe660f5 | ||
|
|
e61c6a1382 | ||
|
|
4ae5503b58 | ||
|
|
7ae46e9b61 | ||
|
|
33a05c7247 | ||
|
|
9b67bc5fe5 | ||
|
|
4ca18c082e | ||
|
|
6aa7afbb6f | ||
|
|
d3bc877a07 | ||
|
|
81bd07fc8b | ||
|
|
d5b813838c | ||
|
|
7bc764d4e0 | ||
|
|
34e965d775 | ||
|
|
7c4ca2bcf9 | ||
|
|
0fb44c074f | ||
|
|
451d3fb2f0 | ||
|
|
7d0b85d727 | ||
|
|
5857d8a7cc | ||
|
|
48de800756 | ||
|
|
dc68a6e30f | ||
|
|
cbcbf635ab | ||
|
|
433d4ddc0c | ||
|
|
9d2a939714 | ||
|
|
c97b56251d | ||
|
|
e041defa67 | ||
|
|
9d5dfa879b | ||
|
|
a511dd1b18 | ||
|
|
a5b6e2c5fd | ||
|
|
2da5763cac | ||
|
|
3e3bb64f4b | ||
|
|
61f0db7713 | ||
|
|
0eba2d1b81 | ||
|
|
9e9bcd24c6 | ||
|
|
c297d8d796 | ||
|
|
c71da496c0 | ||
|
|
d11480197e | ||
|
|
533de1b3c3 | ||
|
|
3d6594a594 | ||
|
|
ee2f0c3cb4 | ||
|
|
9c2d650cb8 | ||
|
|
5c0b66529a | ||
|
|
a2ceb00fbc | ||
|
|
48fc91467b | ||
|
|
c2b746fe15 | ||
|
|
27e8e4ece9 | ||
|
|
e03c0c12a7 | ||
|
|
f8195faaa1 | ||
|
|
accac17b22 | ||
|
|
580b45505b | ||
|
|
24f384d239 | ||
|
|
eaef2ed7de | ||
|
|
4995e8db35 | ||
|
|
16c3df6cad | ||
|
|
42477207e2 | ||
|
|
9b151d06ca | ||
|
|
91fe48d5f7 | ||
|
|
e0abeeb790 | ||
|
|
1302dfcafa | ||
|
|
6c9ed2a655 | ||
|
|
b5ea8b7b02 | ||
|
|
82a3664139 | ||
|
|
b2a78c6188 | ||
|
|
2b4e620813 | ||
|
|
5e702dcd5e | ||
|
|
602d704558 | ||
|
|
38a2808d85 | ||
|
|
5e2f218832 | ||
|
|
2fb8854ff6 | ||
|
|
883bb22b65 | ||
|
|
442fe6afcb | ||
|
|
e64b66054e | ||
|
|
ceb1be9f50 | ||
|
|
7d5ea5ca37 | ||
|
|
d5839fe03c | ||
|
|
de1b7f5e83 | ||
|
|
cf8a348238 | ||
|
|
2197989782 | ||
|
|
5d4fe8efb9 | ||
|
|
638e29bdcc | ||
|
|
d1560b4223 | ||
|
|
6d7224dfee | ||
|
|
f38adfa166 | ||
|
|
7030b15e63 | ||
|
|
ec79820b3f | ||
|
|
b9117c9c50 | ||
|
|
13ef424bf1 | ||
|
|
c0faa75922 | ||
|
|
5d411d257a | ||
|
|
77f4e35bc8 | ||
|
|
b2249827f5 | ||
|
|
f0c5592ba1 | ||
|
|
b92856f41b | ||
|
|
6a90902a4b | ||
|
|
0e9513f2b7 | ||
|
|
283ae7b33e | ||
|
|
102a1c9abc | ||
|
|
32124bce13 | ||
|
|
5f89461a7e | ||
|
|
b00cc483f9 | ||
|
|
705fbefebe | ||
|
|
d448dbd751 | ||
|
|
9d29769536 | ||
|
|
d9f7fd1db8 | ||
|
|
a6d994bf75 | ||
|
|
86aa60a226 | ||
|
|
800f971381 | ||
|
|
341a4558fe | ||
|
|
81b30bf390 | ||
|
|
526eba90e7 | ||
|
|
451a084881 | ||
|
|
a5f60338a2 | ||
|
|
a18896bd63 | ||
|
|
2b457584e0 | ||
|
|
57ee9b4f9c | ||
|
|
45b01d592a | ||
|
|
ef16ee37d9 | ||
|
|
851ab0ad43 | ||
|
|
70380d289f | ||
|
|
4b87964093 | ||
|
|
16809026cd | ||
|
|
c427f3a862 | ||
|
|
07475d2bc1 | ||
|
|
4d80be3a04 | ||
|
|
af06adfd65 | ||
|
|
5ff53db239 | ||
|
|
84b643f80b | ||
|
|
d7d6054b8c | ||
|
|
96bc282759 | ||
|
|
a69d8c63b3 | ||
|
|
0eade51306 | ||
|
|
ea7999e064 | ||
|
|
5f3ff3c44a | ||
|
|
0299bec152 | ||
|
|
61529a6158 | ||
|
|
e5370cddf0 | ||
|
|
c30339debc | ||
|
|
819e7f7e4d | ||
|
|
de2fcc2d87 | ||
|
|
d4892f41b3 | ||
|
|
4d7a4c598a | ||
|
|
d4a163dd39 | ||
|
|
c1e613a9ff | ||
|
|
fcebc4491a | ||
|
|
f75515eedb | ||
|
|
4cea713adf | ||
|
|
148955f725 | ||
|
|
49ef29c9b5 | ||
|
|
62db13ba0e | ||
|
|
d9ed281719 | ||
|
|
56f0cfefa8 | ||
|
|
815c7f45c4 | ||
|
|
4817578ce9 | ||
|
|
13fae28635 | ||
|
|
14907d0752 | ||
|
|
aad5cd7858 | ||
|
|
99a2551046 | ||
|
|
8d31dfb154 | ||
|
|
5e1806aed2 | ||
|
|
72e213ebda | ||
|
|
df242e9468 | ||
|
|
3ce463f482 | ||
|
|
d38e951234 | ||
|
|
1be40e2339 | ||
|
|
bc04e75b4b | ||
|
|
5f7a847822 | ||
|
|
5976a37cf4 | ||
|
|
1cfb793528 | ||
|
|
30bc8ffa8d | ||
|
|
8b7c859d14 | ||
|
|
d1ba50f10e | ||
|
|
bb38e4e599 |
4
.github/workflows/audit.yaml
vendored
4
.github/workflows/audit.yaml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
name: Audit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions-rs/audit-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
7
.github/workflows/build.yaml
vendored
7
.github/workflows/build.yaml
vendored
@@ -13,13 +13,13 @@ jobs:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- "1.66"
|
||||
- "1.70"
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -54,6 +54,9 @@ jobs:
|
||||
- name: Build (sev_snp)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (igvm)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (mshv + kvm)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --no-default-features --features "mshv,kvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
|
||||
2
.github/workflows/dco.yaml
vendored
2
.github/workflows/dco.yaml
vendored
@@ -5,7 +5,7 @@ jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python 3.x
|
||||
uses: actions/setup-python@v1
|
||||
with:
|
||||
|
||||
2
.github/workflows/docker-image.yaml
vendored
2
.github/workflows/docker-image.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
|
||||
12
.github/workflows/fuzz-build.yaml
vendored
12
.github/workflows/fuzz-build.yaml
vendored
@@ -12,9 +12,11 @@ jobs:
|
||||
- nightly
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Rust toolchain (${{ matrix.rust }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
@@ -22,8 +24,8 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- name: Install Cargo fuzz
|
||||
# Temporary fix for cargo-fuzz on latest nightly: https://github.com/rust-fuzz/cargo-fuzz/issues/276
|
||||
#run: cargo install cargo-fuzz
|
||||
run: cargo install --git https://github.com/rust-fuzz/cargo-fuzz --rev b4df3e58f767b5cad8d1aa6753961003f56f3609
|
||||
- name: Cargo Fuzz Build
|
||||
run: cargo install cargo-fuzz
|
||||
- name: Fuzz Build
|
||||
run: cargo fuzz build
|
||||
- name: Fuzz Check
|
||||
run: cargo fuzz check
|
||||
|
||||
26
.github/workflows/gitlint.yaml
vendored
Normal file
26
.github/workflows/gitlint.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Commit messages check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
gitlint:
|
||||
name: Check commit messages
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v3
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install --upgrade gitlint
|
||||
- name: Lint git commit messages
|
||||
run: |
|
||||
gitlint --commits origin/$GITHUB_BASE_REF..
|
||||
2
.github/workflows/hadolint.yaml
vendored
2
.github/workflows/hadolint.yaml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Lint Dockerfile
|
||||
uses: hadolint/hadolint-action@master
|
||||
|
||||
16
.github/workflows/openapi.yaml
vendored
Normal file
16
.github/workflows/openapi.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
name: Cloud Hypervisor OpenAPI Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
Validate:
|
||||
runs-on: ubuntu-latest
|
||||
container: openapitools/openapi-generator-cli
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Validate OpenAPI
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
/usr/local/bin/docker-entrypoint.sh validate -i vmm/src/api/openapi/cloud-hypervisor.yaml
|
||||
12
.github/workflows/quality.yaml
vendored
12
.github/workflows/quality.yaml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
experimental: true
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@@ -109,6 +109,14 @@ jobs:
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "sev_snp" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (igvm)
|
||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ matrix.target != 'x86_64-unknown-linux-gnu' }}
|
||||
command: clippy
|
||||
args: --target=${{ matrix.target }} --locked --all --all-targets --no-default-features --tests --examples --features "igvm" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Clippy (kvm + tdx)
|
||||
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
|
||||
uses: actions-rs/cargo@v1
|
||||
@@ -125,6 +133,6 @@ jobs:
|
||||
name: Typos / Spellcheck
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
# Executes "typos ."
|
||||
- uses: crate-ci/typos@v1.16.11
|
||||
|
||||
12
.github/workflows/release.yaml
vendored
12
.github/workflows/release.yaml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Code checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
- name: Install musl-gcc
|
||||
run: sudo apt install -y musl-tools
|
||||
- name: Create release directory
|
||||
@@ -16,29 +16,29 @@ jobs:
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.67.1"
|
||||
toolchain: "1.70"
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.67.1"
|
||||
toolchain: "1.70"
|
||||
target: x86_64-unknown-linux-musl
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.67.1"
|
||||
toolchain: "1.70"
|
||||
command: build
|
||||
args: --all --release --features mshv --target=x86_64-unknown-linux-gnu
|
||||
- name: Static Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.67.1"
|
||||
toolchain: "1.70"
|
||||
command: build
|
||||
args: --all --release --features mshv --target=x86_64-unknown-linux-musl
|
||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.67.1"
|
||||
toolchain: "1.70"
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Create Release
|
||||
|
||||
20
.github/workflows/shlint.yaml
vendored
Normal file
20
.github/workflows/shlint.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Shell scripts check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
sh-checker:
|
||||
name: Check shell scripts
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Run the shell script checkers
|
||||
uses: luizm/action-sh-checker@master
|
||||
env:
|
||||
SHFMT_OPTS: -i 4 -d
|
||||
SHELLCHECK_OPTS: -x --source-path scripts
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@
|
||||
**/rusty-tags.vi
|
||||
/rpm/SOURCES
|
||||
/.vscode
|
||||
/vendor
|
||||
|
||||
15
.gitlint
Normal file
15
.gitlint
Normal file
@@ -0,0 +1,15 @@
|
||||
[general]
|
||||
extra-path=scripts/gitlint/rules.py
|
||||
regex-style-search=true
|
||||
|
||||
[ignore-by-author-name]
|
||||
regex=dependabot
|
||||
ignore=all
|
||||
|
||||
# default 72
|
||||
[title-max-length]
|
||||
line-length=72
|
||||
|
||||
# default 80
|
||||
[body-max-line-length]
|
||||
line-length=72
|
||||
601
Cargo.lock
generated
601
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
34
Cargo.toml
34
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "36.0.0"
|
||||
version = "38.0.0"
|
||||
authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
default-run = "cloud-hypervisor"
|
||||
@@ -15,7 +15,7 @@ homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||
# a.) A dependency requires it,
|
||||
# b.) If we want to use a new feature and that MSRV is at least 6 months old,
|
||||
# c.) There is a security issue that is addressed by the toolchain update.
|
||||
rust-version = "1.66"
|
||||
rust-version = "1.70"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
@@ -29,38 +29,37 @@ strip = false
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
api_client = { path = "api_client" }
|
||||
clap = { version = "4.3.11", features = ["string"] }
|
||||
dhat = { version = "0.3.2", optional = true }
|
||||
clap = { version = "4.4.7", features = ["string"] }
|
||||
dhat = { version = "0.3.3", optional = true }
|
||||
epoll = "4.3.3"
|
||||
event_monitor = { path = "event_monitor" }
|
||||
hypervisor = { path = "hypervisor" }
|
||||
libc = "0.2.147"
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
libc = "0.2.153"
|
||||
log = { version = "0.4.20", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.4.0"
|
||||
serde_json = "1.0.107"
|
||||
serde_json = "1.0.109"
|
||||
signal-hook = "0.3.17"
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.52"
|
||||
tpm = { path = "tpm"}
|
||||
tracer = { path = "tracer" }
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.12.2"
|
||||
vmm-sys-util = "0.12.1"
|
||||
vm-memory = "0.14.0"
|
||||
zbus = { version = "3.11.1", optional = true }
|
||||
|
||||
# List of patched crates
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.7.0" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" }
|
||||
|
||||
[dev-dependencies]
|
||||
dirs = "5.0.0"
|
||||
net_util = { path = "net_util" }
|
||||
once_cell = "1.18.0"
|
||||
serde_json = "1.0.107"
|
||||
once_cell = "1.19.0"
|
||||
serde_json = "1.0.109"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -71,10 +70,11 @@ default = ["kvm", "io_uring"]
|
||||
dbus_api = ["zbus", "vmm/dbus_api"]
|
||||
dhat-heap = ["dhat"] # For heap profiling
|
||||
guest_debug = ["vmm/guest_debug"]
|
||||
igvm = ["vmm/igvm", "mshv"]
|
||||
io_uring = ["vmm/io_uring"]
|
||||
kvm = ["vmm/kvm"]
|
||||
mshv = ["vmm/mshv"]
|
||||
sev_snp = ["vmm/sev_snp", "mshv"]
|
||||
sev_snp = ["igvm", "vmm/sev_snp", "mshv"]
|
||||
tdx = ["vmm/tdx"]
|
||||
tracing = ["vmm/tracing", "tracer/tracing"]
|
||||
|
||||
|
||||
35
Jenkinsfile
vendored
35
Jenkinsfile
vendored
@@ -53,6 +53,9 @@ pipeline {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
@@ -64,11 +67,6 @@ pipeline {
|
||||
sh 'scripts/prepare_vdpa.sh'
|
||||
}
|
||||
}
|
||||
stage('Run OpenAPI tests') {
|
||||
steps {
|
||||
sh 'scripts/run_openapi_tests.sh'
|
||||
}
|
||||
}
|
||||
stage('Run unit tests') {
|
||||
steps {
|
||||
sh 'scripts/dev_cli.sh tests --unit'
|
||||
@@ -125,6 +123,9 @@ pipeline {
|
||||
return runWorkers
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
@@ -142,7 +143,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration -- -- --skip common_parallel::test_vfio'
|
||||
sh 'scripts/dev_cli.sh tests --integration'
|
||||
}
|
||||
}
|
||||
stage('Run live-migration integration tests') {
|
||||
@@ -160,7 +161,7 @@ pipeline {
|
||||
}
|
||||
steps {
|
||||
sh 'sudo modprobe openvswitch'
|
||||
sh 'scripts/dev_cli.sh tests --integration --libc musl -- -- --skip common_parallel::test_vfio'
|
||||
sh 'scripts/dev_cli.sh tests --integration --libc musl'
|
||||
}
|
||||
}
|
||||
stage('Run live-migration integration tests for musl') {
|
||||
@@ -364,6 +365,9 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
@@ -405,6 +409,9 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
environment {
|
||||
AUTH_DOWNLOAD_TOKEN = credentials('8a26fd74-d40e-414c-9132-ff3f867806ef')
|
||||
}
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
@@ -505,5 +512,19 @@ def boolean skipWorkerBuild() {
|
||||
return true
|
||||
}
|
||||
|
||||
if (sh(
|
||||
returnStatus: true,
|
||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '^\\.'"
|
||||
) != 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (sh(
|
||||
returnStatus: true,
|
||||
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v 'gitlint'"
|
||||
) != 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -10,20 +10,20 @@ sev_snp = []
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.147"
|
||||
linux-loader = { version = "0.9.1", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.40"
|
||||
libc = "0.2.153"
|
||||
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.20"
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.52"
|
||||
uuid = "1.3.4"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-bitmap"] }
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
fdt_parser = { version = "0.1.4", package = "fdt" }
|
||||
|
||||
@@ -111,8 +111,9 @@ pub const RAM_64BIT_START: GuestAddress = GuestAddress(0x1_0000_0000);
|
||||
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;
|
||||
/// Maximum size of the device tree blob as specified in [the kernel
|
||||
/// documentation](https://www.kernel.org/doc/Documentation/arm64/booting.txt).
|
||||
pub const FDT_MAX_SIZE: u64 = 0x20_0000;
|
||||
|
||||
/// Put ACPI table above dtb
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// Copyright 2020 Arm Limited (or its affiliates). All rights reserved.
|
||||
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
use std::os::fd::AsFd;
|
||||
use std::result;
|
||||
use vm_memory::{Bytes, GuestAddress, GuestMemory};
|
||||
use vm_memory::{GuestAddress, GuestMemory};
|
||||
|
||||
/// Errors thrown while loading UEFI binary
|
||||
#[derive(Debug)]
|
||||
@@ -24,7 +25,7 @@ pub fn load_uefi<F, M: GuestMemory>(
|
||||
uefi_image: &mut F,
|
||||
) -> Result<()>
|
||||
where
|
||||
F: Read + Seek,
|
||||
F: Read + Seek + AsFd,
|
||||
{
|
||||
let uefi_size = uefi_image
|
||||
.seek(SeekFrom::End(0))
|
||||
@@ -36,6 +37,6 @@ where
|
||||
}
|
||||
uefi_image.rewind().map_err(|_| Error::SeekUefiStart)?;
|
||||
guest_mem
|
||||
.read_exact_from(guest_addr, uefi_image, uefi_size)
|
||||
.read_exact_volatile_from(guest_addr, &mut uefi_image.as_fd(), uefi_size)
|
||||
.map_err(|_| Error::ReadUefiImage)
|
||||
}
|
||||
|
||||
@@ -91,8 +91,9 @@ pub mod x86_64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::{
|
||||
arch_memory_regions, configure_system, configure_vcpu, generate_common_cpuid,
|
||||
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||
layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry, EntryPoint, _NSIG,
|
||||
generate_ram_ranges, get_host_cpu_phys_bits, initramfs_load_addr, layout,
|
||||
layout::CMDLINE_MAX_SIZE, layout::CMDLINE_START, regs, CpuidConfig, CpuidFeatureEntry,
|
||||
EntryPoint, _NSIG,
|
||||
};
|
||||
|
||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||
|
||||
@@ -17,14 +17,13 @@ use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::{CpuVendor, HypervisorCpuError, HypervisorError};
|
||||
use linux_loader::loader::bootparam::boot_params;
|
||||
use linux_loader::loader::elf::start_info::{
|
||||
hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info,
|
||||
};
|
||||
use std::collections::BTreeMap;
|
||||
use std::mem;
|
||||
use vm_memory::{
|
||||
Address, ByteValued, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
Address, Bytes, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic,
|
||||
GuestMemoryRegion, GuestUsize,
|
||||
};
|
||||
mod smbios;
|
||||
@@ -116,38 +115,6 @@ impl SgxEpcRegion {
|
||||
}
|
||||
}
|
||||
|
||||
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
||||
// trait (in this case `DataInit`) where:
|
||||
// * the type that is implementing the trait is foreign or
|
||||
// * all of the parameters being passed to the trait (if there are any) are also foreign
|
||||
// is prohibited.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct StartInfoWrapper(hvm_start_info);
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct MemmapTableEntryWrapper(hvm_memmap_table_entry);
|
||||
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct ModlistEntryWrapper(hvm_modlist_entry);
|
||||
|
||||
// SAFETY: data structure only contain a series of integers
|
||||
unsafe impl ByteValued for StartInfoWrapper {}
|
||||
// SAFETY: data structure only contain a series of integers
|
||||
unsafe impl ByteValued for MemmapTableEntryWrapper {}
|
||||
// SAFETY: data structure only contain a series of integers
|
||||
unsafe impl ByteValued for ModlistEntryWrapper {}
|
||||
|
||||
// This is a workaround to the Rust enforcement specifying that any implementation of a foreign
|
||||
// trait (in this case `DataInit`) where:
|
||||
// * the type that is implementing the trait is foreign or
|
||||
// * all of the parameters being passed to the trait (if there are any) are also foreign
|
||||
// is prohibited.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
struct BootParamsWrapper(boot_params);
|
||||
|
||||
// SAFETY: BootParamsWrap is a wrapper over `boot_params` (a series of ints).
|
||||
unsafe impl ByteValued for BootParamsWrapper {}
|
||||
|
||||
pub struct CpuidConfig {
|
||||
pub sgx_epc_sections: Option<Vec<SgxEpcSection>>,
|
||||
pub phys_bits: u8,
|
||||
@@ -221,6 +188,26 @@ impl From<Error> for super::Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_x2apic_id(cpu_id: u32, topology: Option<(u8, u8, u8)>) -> u32 {
|
||||
if let Some(t) = topology {
|
||||
let thread_mask_width = u8::BITS - (t.0 - 1).leading_zeros();
|
||||
let core_mask_width = u8::BITS - (t.1 - 1).leading_zeros();
|
||||
let die_mask_width = u8::BITS - (t.2 - 1).leading_zeros();
|
||||
|
||||
let thread_id = cpu_id % (t.0 as u32);
|
||||
let core_id = cpu_id / (t.0 as u32) % (t.1 as u32);
|
||||
let die_id = cpu_id / ((t.0 * t.1) as u32) % (t.2 as u32);
|
||||
let socket_id = cpu_id / ((t.0 * t.1 * t.2) as u32);
|
||||
|
||||
return thread_id
|
||||
| (core_id << thread_mask_width)
|
||||
| (die_id << (thread_mask_width + core_mask_width))
|
||||
| (socket_id << (thread_mask_width + core_mask_width + die_mask_width));
|
||||
}
|
||||
|
||||
cpu_id
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CpuidReg {
|
||||
EAX,
|
||||
@@ -240,6 +227,26 @@ pub struct CpuidPatch {
|
||||
}
|
||||
|
||||
impl CpuidPatch {
|
||||
pub fn get_cpuid_reg(
|
||||
cpuid: &[CpuIdEntry],
|
||||
function: u32,
|
||||
index: Option<u32>,
|
||||
reg: CpuidReg,
|
||||
) -> Option<u32> {
|
||||
for entry in cpuid.iter() {
|
||||
if entry.function == function && (index.is_none() || index.unwrap() == entry.index) {
|
||||
return match reg {
|
||||
CpuidReg::EAX => Some(entry.eax),
|
||||
CpuidReg::EBX => Some(entry.ebx),
|
||||
CpuidReg::ECX => Some(entry.ecx),
|
||||
CpuidReg::EDX => Some(entry.edx),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn set_cpuid_reg(
|
||||
cpuid: &mut Vec<CpuIdEntry>,
|
||||
function: u32,
|
||||
@@ -777,31 +784,27 @@ pub fn configure_vcpu(
|
||||
cpu_vendor: CpuVendor,
|
||||
topology: Option<(u8, u8, u8)>,
|
||||
) -> super::Result<()> {
|
||||
let x2apic_id = get_x2apic_id(id as u32, topology);
|
||||
|
||||
// Per vCPU CPUID changes; common are handled via generate_common_cpuid()
|
||||
let mut cpuid = cpuid;
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, u32::from(id));
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, u32::from(id));
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0xb, None, CpuidReg::EDX, x2apic_id);
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1f, None, CpuidReg::EDX, x2apic_id);
|
||||
if matches!(cpu_vendor, CpuVendor::AMD) {
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
&mut cpuid,
|
||||
0x8000_001e,
|
||||
Some(0),
|
||||
CpuidReg::EAX,
|
||||
u32::from(id),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(t) = topology {
|
||||
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2, cpu_vendor, id);
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x8000_001e, Some(0), CpuidReg::EAX, x2apic_id);
|
||||
}
|
||||
|
||||
// Set ApicId in cpuid for each vcpu
|
||||
// SAFETY: get host cpuid when eax=1
|
||||
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||
cpu_ebx &= 0xffffff;
|
||||
cpu_ebx |= (id as u32) << 24;
|
||||
cpu_ebx |= x2apic_id << 24;
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||
|
||||
if let Some(t) = topology {
|
||||
update_cpuid_topology(&mut cpuid, t.0, t.1, t.2, cpu_vendor, id);
|
||||
}
|
||||
|
||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||
if !kvm_hyperv {
|
||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||
@@ -896,6 +899,7 @@ pub fn configure_system(
|
||||
serial_number: Option<&str>,
|
||||
uuid: Option<&str>,
|
||||
oem_strings: Option<&[&str]>,
|
||||
topology: Option<(u8, u8, u8)>,
|
||||
) -> super::Result<()> {
|
||||
// Write EBDA address to location where ACPICA expects to find it
|
||||
guest_mem
|
||||
@@ -908,7 +912,7 @@ pub fn configure_system(
|
||||
// Place the MP table after the SMIOS table aligned to 16 bytes
|
||||
let offset = GuestAddress(layout::SMBIOS_START).unchecked_add(size);
|
||||
let offset = GuestAddress((offset.0 + 16) & !0xf);
|
||||
mptable::setup_mptable(offset, guest_mem, _num_cpus).map_err(Error::MpTableSetup)?;
|
||||
mptable::setup_mptable(offset, guest_mem, _num_cpus, topology).map_err(Error::MpTableSetup)?;
|
||||
|
||||
// Check that the RAM is not smaller than the RSDP start address
|
||||
if let Some(rsdp_addr) = rsdp_addr {
|
||||
@@ -926,52 +930,11 @@ pub fn configure_system(
|
||||
)
|
||||
}
|
||||
|
||||
fn configure_pvh(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline_addr: GuestAddress,
|
||||
initramfs: &Option<InitramfsConfig>,
|
||||
rsdp_addr: Option<GuestAddress>,
|
||||
sgx_epc_region: Option<SgxEpcRegion>,
|
||||
) -> super::Result<()> {
|
||||
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
||||
|
||||
let mut start_info: StartInfoWrapper = StartInfoWrapper(hvm_start_info::default());
|
||||
|
||||
start_info.0.magic = XEN_HVM_START_MAGIC_VALUE;
|
||||
start_info.0.version = 1; // pvh has version 1
|
||||
start_info.0.nr_modules = 0;
|
||||
start_info.0.cmdline_paddr = cmdline_addr.raw_value();
|
||||
start_info.0.memmap_paddr = layout::MEMMAP_START.raw_value();
|
||||
|
||||
if let Some(rsdp_addr) = rsdp_addr {
|
||||
start_info.0.rsdp_paddr = rsdp_addr.0;
|
||||
}
|
||||
|
||||
if let Some(initramfs_config) = initramfs {
|
||||
// The initramfs has been written to guest memory already, here we just need to
|
||||
// create the module structure that describes it.
|
||||
let ramdisk_mod: ModlistEntryWrapper = ModlistEntryWrapper(hvm_modlist_entry {
|
||||
paddr: initramfs_config.address.raw_value(),
|
||||
size: initramfs_config.size as u64,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
start_info.0.nr_modules += 1;
|
||||
start_info.0.modlist_paddr = layout::MODLIST_START.raw_value();
|
||||
|
||||
// Write the modlist struct to guest memory.
|
||||
guest_mem
|
||||
.write_obj(ramdisk_mod, layout::MODLIST_START)
|
||||
.map_err(super::Error::ModlistSetup)?;
|
||||
}
|
||||
|
||||
// Vector to hold the memory maps which needs to be written to guest memory
|
||||
// at MEMMAP_START after all of the mappings are recorded.
|
||||
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
|
||||
|
||||
// Create the memory map entries.
|
||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||
type RamRange = (u64, u64);
|
||||
|
||||
/// Returns usable physical memory ranges for the guest
|
||||
/// These should be used to create e820_RAM memory maps
|
||||
pub fn generate_ram_ranges(guest_mem: &GuestMemoryMmap) -> super::Result<Vec<RamRange>> {
|
||||
// Merge continuous memory regions into one region.
|
||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||
let ram_regions = {
|
||||
@@ -1004,16 +967,12 @@ fn configure_pvh(
|
||||
ram_regions
|
||||
};
|
||||
|
||||
if ram_regions.len() > 2 {
|
||||
error!(
|
||||
"There should be up to two non-continuous regions, devidided by the
|
||||
gap at the end of 32bit address space (e.g. between 3G and 4G)."
|
||||
);
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region before the gap
|
||||
{
|
||||
let mut ram_ranges = vec![];
|
||||
|
||||
// Generate the first usable physical memory range before the gap. The e820 map
|
||||
// should only report memory above 1MiB.
|
||||
let first_ram_range = {
|
||||
let (first_region_start, first_region_end) =
|
||||
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
||||
let high_ram_start = layout::HIGH_RAM_START.raw_value();
|
||||
@@ -1033,39 +992,87 @@ fn configure_pvh(
|
||||
}
|
||||
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
|
||||
"first usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
|
||||
high_ram_start, first_region_end
|
||||
);
|
||||
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
high_ram_start,
|
||||
first_region_end - high_ram_start,
|
||||
E820_RAM,
|
||||
(high_ram_start, *first_region_end)
|
||||
};
|
||||
ram_ranges.push(first_ram_range);
|
||||
|
||||
// Generate additional usable physical memory range after the gap if any.
|
||||
for ram_region in ram_regions.iter().skip(1) {
|
||||
info!(
|
||||
"found usable physical memory range, start: 0x{:08x}, end: 0x{:08x}",
|
||||
ram_region.0, ram_region.1
|
||||
);
|
||||
|
||||
ram_ranges.push(*ram_region);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region after the gap if any
|
||||
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
|
||||
Ok(ram_ranges)
|
||||
}
|
||||
|
||||
if second_region_start != &ram_64bit_start {
|
||||
error!(
|
||||
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||
second_region_start, ram_64bit_start
|
||||
);
|
||||
fn configure_pvh(
|
||||
guest_mem: &GuestMemoryMmap,
|
||||
cmdline_addr: GuestAddress,
|
||||
initramfs: &Option<InitramfsConfig>,
|
||||
rsdp_addr: Option<GuestAddress>,
|
||||
sgx_epc_region: Option<SgxEpcRegion>,
|
||||
) -> super::Result<()> {
|
||||
const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
|
||||
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
let mut start_info = hvm_start_info {
|
||||
magic: XEN_HVM_START_MAGIC_VALUE,
|
||||
version: 1, // pvh has version 1
|
||||
nr_modules: 0,
|
||||
cmdline_paddr: cmdline_addr.raw_value(),
|
||||
memmap_paddr: layout::MEMMAP_START.raw_value(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(rsdp_addr) = rsdp_addr {
|
||||
start_info.rsdp_paddr = rsdp_addr.0;
|
||||
}
|
||||
|
||||
if let Some(initramfs_config) = initramfs {
|
||||
// The initramfs has been written to guest memory already, here we just need to
|
||||
// create the module structure that describes it.
|
||||
let ramdisk_mod = hvm_modlist_entry {
|
||||
paddr: initramfs_config.address.raw_value(),
|
||||
size: initramfs_config.size as u64,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
start_info.nr_modules += 1;
|
||||
start_info.modlist_paddr = layout::MODLIST_START.raw_value();
|
||||
|
||||
// Write the modlist struct to guest memory.
|
||||
guest_mem
|
||||
.write_obj(ramdisk_mod, layout::MODLIST_START)
|
||||
.map_err(super::Error::ModlistSetup)?;
|
||||
}
|
||||
|
||||
// Vector to hold the memory maps which needs to be written to guest memory
|
||||
// at MEMMAP_START after all of the mappings are recorded.
|
||||
let mut memmap: Vec<hvm_memmap_table_entry> = Vec::new();
|
||||
|
||||
// Create the memory map entries.
|
||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||
|
||||
// Get usable physical memory ranges
|
||||
let ram_ranges = generate_ram_ranges(guest_mem)?;
|
||||
|
||||
// Create e820 memory map entries
|
||||
for ram_range in ram_ranges {
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x}",
|
||||
ram_64bit_start, second_region_end
|
||||
ram_range.0, ram_range.1
|
||||
);
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
ram_64bit_start,
|
||||
second_region_end - ram_64bit_start,
|
||||
ram_range.0,
|
||||
ram_range.1 - ram_range.0,
|
||||
E820_RAM,
|
||||
);
|
||||
}
|
||||
@@ -1086,7 +1093,7 @@ fn configure_pvh(
|
||||
);
|
||||
}
|
||||
|
||||
start_info.0.memmap_entries = memmap.len() as u32;
|
||||
start_info.memmap_entries = memmap.len() as u32;
|
||||
|
||||
// Copy the vector with the memmap table to the MEMMAP_START address
|
||||
// which is already saved in the memmap_paddr field of hvm_start_info struct.
|
||||
@@ -1095,17 +1102,14 @@ fn configure_pvh(
|
||||
guest_mem
|
||||
.checked_offset(
|
||||
memmap_start_addr,
|
||||
mem::size_of::<hvm_memmap_table_entry>() * start_info.0.memmap_entries as usize,
|
||||
mem::size_of::<hvm_memmap_table_entry>() * start_info.memmap_entries as usize,
|
||||
)
|
||||
.ok_or(super::Error::MemmapTablePastRamEnd)?;
|
||||
|
||||
// For every entry in the memmap vector, create a MemmapTableEntryWrapper
|
||||
// and write it to guest memory.
|
||||
// For every entry in the memmap vector, write it to guest memory.
|
||||
for memmap_entry in memmap {
|
||||
let map_entry_wrapper: MemmapTableEntryWrapper = MemmapTableEntryWrapper(memmap_entry);
|
||||
|
||||
guest_mem
|
||||
.write_obj(map_entry_wrapper, memmap_start_addr)
|
||||
.write_obj(memmap_entry, memmap_start_addr)
|
||||
.map_err(|_| super::Error::MemmapTableSetup)?;
|
||||
memmap_start_addr =
|
||||
memmap_start_addr.unchecked_add(mem::size_of::<hvm_memmap_table_entry>() as u64);
|
||||
@@ -1191,10 +1195,24 @@ fn update_cpuid_topology(
|
||||
cpu_vendor: CpuVendor,
|
||||
id: u8,
|
||||
) {
|
||||
let x2apic_id = get_x2apic_id(
|
||||
id as u32,
|
||||
Some((threads_per_core, cores_per_die, dies_per_package)),
|
||||
);
|
||||
|
||||
let thread_width = 8 - (threads_per_core - 1).leading_zeros();
|
||||
let core_width = (8 - (cores_per_die - 1).leading_zeros()) + thread_width;
|
||||
let die_width = (8 - (dies_per_package - 1).leading_zeros()) + core_width;
|
||||
|
||||
let mut cpu_ebx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX).unwrap_or(0);
|
||||
cpu_ebx |= ((dies_per_package as u32) * (cores_per_die as u32) * (threads_per_core as u32))
|
||||
& 0xff << 16;
|
||||
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||
|
||||
let mut cpu_edx = CpuidPatch::get_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX).unwrap_or(0);
|
||||
cpu_edx |= 1 << 28;
|
||||
CpuidPatch::set_cpuid_reg(cpuid, 0x1, None, CpuidReg::EDX, cpu_edx);
|
||||
|
||||
// CPU Topology leaf 0xb
|
||||
CpuidPatch::set_cpuid_reg(cpuid, 0xb, Some(0), CpuidReg::EAX, thread_width);
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
@@ -1253,7 +1271,7 @@ fn update_cpuid_topology(
|
||||
0x8000_001e,
|
||||
Some(0),
|
||||
CpuidReg::EBX,
|
||||
((threads_per_core as u32 - 1) << 8) | (id as u32 & 0xff),
|
||||
((threads_per_core as u32 - 1) << 8) | (x2apic_id & 0xff),
|
||||
);
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
cpuid,
|
||||
@@ -1264,21 +1282,21 @@ fn update_cpuid_topology(
|
||||
);
|
||||
CpuidPatch::set_cpuid_reg(cpuid, 0x8000_001e, Some(0), CpuidReg::EDX, 0);
|
||||
if cores_per_die * threads_per_core > 1 {
|
||||
let ecx =
|
||||
CpuidPatch::get_cpuid_reg(cpuid, 0x8000_0001, Some(0), CpuidReg::ECX).unwrap_or(0);
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
cpuid,
|
||||
0x8000_0001,
|
||||
Some(0),
|
||||
CpuidReg::ECX,
|
||||
(1u32 << 1) | (1u32 << 22),
|
||||
ecx | (1u32 << 1) | (1u32 << 22),
|
||||
);
|
||||
CpuidPatch::set_cpuid_reg(
|
||||
cpuid,
|
||||
0x0000_0001,
|
||||
Some(0),
|
||||
CpuidReg::EBX,
|
||||
((id as u32) << 24)
|
||||
| (8 << 8)
|
||||
| (((cores_per_die * threads_per_core) as u32) << 16),
|
||||
(x2apic_id << 24) | (8 << 8) | (((cores_per_die * threads_per_core) as u32) << 16),
|
||||
);
|
||||
let cpuid_patches = vec![
|
||||
// Patch tsc deadline timer bit
|
||||
@@ -1311,7 +1329,7 @@ fn update_cpuid_topology(
|
||||
// sections exposed to the guest.
|
||||
fn update_cpuid_sgx(
|
||||
cpuid: &mut Vec<CpuIdEntry>,
|
||||
epc_sections: &Vec<SgxEpcSection>,
|
||||
epc_sections: &[SgxEpcSection],
|
||||
) -> Result<(), Error> {
|
||||
// Something's wrong if there's no EPC section.
|
||||
if epc_sections.is_empty() {
|
||||
@@ -1383,6 +1401,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
);
|
||||
assert!(config_err.is_err());
|
||||
|
||||
@@ -1405,6 +1424,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1432,6 +1452,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1445,6 +1466,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -1473,4 +1495,25 @@ mod tests {
|
||||
|
||||
assert_eq!(format!("{memmap:?}"), format!("{expected_memmap:?}"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_x2apic_id() {
|
||||
let x2apic_id = get_x2apic_id(0, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 0);
|
||||
|
||||
let x2apic_id = get_x2apic_id(1, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 1);
|
||||
|
||||
let x2apic_id = get_x2apic_id(2, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 2);
|
||||
|
||||
let x2apic_id = get_x2apic_id(6, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 8);
|
||||
|
||||
let x2apic_id = get_x2apic_id(7, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 9);
|
||||
|
||||
let x2apic_id = get_x2apic_id(8, Some((2, 3, 1)));
|
||||
assert_eq!(x2apic_id, 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
// found in the LICENSE-BSD-3-Clause file.
|
||||
|
||||
use crate::layout::{APIC_START, HIGH_RAM_START, IOAPIC_START};
|
||||
use crate::x86_64::mpspec;
|
||||
use crate::x86_64::{get_x2apic_id, mpspec};
|
||||
use crate::GuestMemoryMmap;
|
||||
use libc::c_char;
|
||||
use std::io;
|
||||
use std::mem;
|
||||
use std::result;
|
||||
use std::slice;
|
||||
@@ -126,9 +125,18 @@ fn compute_mp_size(num_cpus: u8) -> usize {
|
||||
}
|
||||
|
||||
/// Performs setup of the MP table for the given `num_cpus`.
|
||||
pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8) -> Result<()> {
|
||||
if num_cpus as u32 > MAX_SUPPORTED_CPUS {
|
||||
return Err(Error::TooManyCpus);
|
||||
pub fn setup_mptable(
|
||||
offset: GuestAddress,
|
||||
mem: &GuestMemoryMmap,
|
||||
num_cpus: u8,
|
||||
topology: Option<(u8, u8, u8)>,
|
||||
) -> Result<()> {
|
||||
if num_cpus > 0 {
|
||||
let cpu_id_max = num_cpus - 1;
|
||||
let x2apic_id_max = get_x2apic_id(cpu_id_max.into(), topology);
|
||||
if x2apic_id_max >= MAX_SUPPORTED_CPUS {
|
||||
return Err(Error::TooManyCpus);
|
||||
}
|
||||
}
|
||||
|
||||
// Used to keep track of the next base pointer into the MP table.
|
||||
@@ -142,7 +150,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
||||
}
|
||||
|
||||
let mut checksum: u8 = 0;
|
||||
let ioapicid: u8 = num_cpus + 1;
|
||||
let ioapicid: u8 = MAX_SUPPORTED_CPUS as u8 + 1;
|
||||
|
||||
// The checked_add here ensures the all of the following base_mp.unchecked_add's will be without
|
||||
// overflow.
|
||||
@@ -154,7 +162,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
||||
return Err(Error::AddressOverflow);
|
||||
}
|
||||
|
||||
mem.read_exact_from(base_mp, &mut io::repeat(0), mp_size)
|
||||
mem.read_exact_volatile_from(base_mp, &mut vec![0; mp_size].as_slice(), mp_size)
|
||||
.map_err(Error::Clear)?;
|
||||
|
||||
{
|
||||
@@ -180,7 +188,7 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
||||
for cpu_id in 0..num_cpus {
|
||||
let mut mpc_cpu = MpcCpuWrapper(mpspec::mpc_cpu::default());
|
||||
mpc_cpu.0.type_ = mpspec::MP_PROCESSOR as u8;
|
||||
mpc_cpu.0.apicid = cpu_id;
|
||||
mpc_cpu.0.apicid = get_x2apic_id(cpu_id as u32, topology) as u8;
|
||||
mpc_cpu.0.apicver = APIC_VERSION;
|
||||
mpc_cpu.0.cpuflag = mpspec::CPU_ENABLED as u8
|
||||
| if cpu_id == 0 {
|
||||
@@ -291,7 +299,10 @@ pub fn setup_mptable(offset: GuestAddress, mem: &GuestMemoryMmap, num_cpus: u8)
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::layout::MPTABLE_START;
|
||||
use vm_memory::{GuestAddress, GuestUsize};
|
||||
use vm_memory::{
|
||||
bitmap::BitmapSlice, GuestAddress, GuestUsize, VolatileMemoryError, VolatileSlice,
|
||||
WriteVolatile,
|
||||
};
|
||||
|
||||
fn table_entry_size(type_: u8) -> usize {
|
||||
match type_ as u32 {
|
||||
@@ -310,7 +321,7 @@ mod tests {
|
||||
let mem =
|
||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -319,7 +330,7 @@ mod tests {
|
||||
let mem = GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus) - 1)])
|
||||
.unwrap();
|
||||
|
||||
assert!(setup_mptable(MPTABLE_START, &mem, num_cpus).is_err());
|
||||
assert!(setup_mptable(MPTABLE_START, &mem, num_cpus, None).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -328,7 +339,7 @@ mod tests {
|
||||
let mem =
|
||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||
|
||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||
|
||||
@@ -344,27 +355,31 @@ mod tests {
|
||||
let mem =
|
||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(num_cpus))]).unwrap();
|
||||
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus).unwrap();
|
||||
setup_mptable(MPTABLE_START, &mem, num_cpus, None).unwrap();
|
||||
|
||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
||||
let mpc_table: MpcTableWrapper = mem.read_obj(mpc_offset).unwrap();
|
||||
|
||||
struct Sum(u8);
|
||||
impl io::Write for Sum {
|
||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||
for v in buf.iter() {
|
||||
impl WriteVolatile for Sum {
|
||||
fn write_volatile<B: BitmapSlice>(
|
||||
&mut self,
|
||||
buf: &VolatileSlice<B>,
|
||||
) -> result::Result<usize, VolatileMemoryError> {
|
||||
let mut tmp = vec![0u8; buf.len()];
|
||||
tmp.write_all_volatile(buf)?;
|
||||
|
||||
for v in tmp.iter() {
|
||||
self.0 = self.0.wrapping_add(*v);
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
fn flush(&mut self) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let mut sum = Sum(0);
|
||||
mem.write_to(mpc_offset, &mut sum, mpc_table.0.length as usize)
|
||||
mem.write_volatile_to(mpc_offset, &mut sum, mpc_table.0.length as usize)
|
||||
.unwrap();
|
||||
assert_eq!(sum.0, 0);
|
||||
}
|
||||
@@ -378,7 +393,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
for i in 0..MAX_SUPPORTED_CPUS as u8 {
|
||||
setup_mptable(MPTABLE_START, &mem, i).unwrap();
|
||||
setup_mptable(MPTABLE_START, &mem, i, None).unwrap();
|
||||
|
||||
let mpf_intel: MpfIntelWrapper = mem.read_obj(MPTABLE_START).unwrap();
|
||||
let mpc_offset = GuestAddress(mpf_intel.0.physptr as GuestUsize);
|
||||
@@ -411,7 +426,7 @@ mod tests {
|
||||
let mem =
|
||||
GuestMemoryMmap::from_ranges(&[(MPTABLE_START, compute_mp_size(cpus as u8))]).unwrap();
|
||||
|
||||
let result = setup_mptable(MPTABLE_START, &mem, cpus as u8);
|
||||
let result = setup_mptable(MPTABLE_START, &mem, cpus as u8, None);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,18 +10,18 @@ io_uring = ["dep:io-uring"]
|
||||
|
||||
[dependencies]
|
||||
byteorder = "1.4.3"
|
||||
crc32c = "0.6.4"
|
||||
io-uring = { version = "0.6.1", optional = true }
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
crc-any = "2.4.4"
|
||||
io-uring = { version = "0.6.2", optional = true }
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
remain = "0.2.11"
|
||||
smallvec = "1.11.0"
|
||||
thiserror = "1.0.40"
|
||||
smallvec = "1.13.1"
|
||||
thiserror = "1.0.52"
|
||||
uuid = { version = "1.3.4", features = ["v4"] }
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.9.0"
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.11.0"
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -143,10 +143,14 @@ pub enum ExecuteError {
|
||||
Flush(io::Error),
|
||||
#[error("Failed to read: {0}")]
|
||||
Read(GuestMemoryError),
|
||||
#[error("Failed to read_exact: {0}")]
|
||||
ReadExact(io::Error),
|
||||
#[error("Failed to seek: {0}")]
|
||||
Seek(io::Error),
|
||||
#[error("Failed to write: {0}")]
|
||||
Write(GuestMemoryError),
|
||||
#[error("Failed to write_all: {0}")]
|
||||
WriteAll(io::Error),
|
||||
#[error("Unsupported request: {0}")]
|
||||
Unsupported(u32),
|
||||
#[error("Failed to submit io uring: {0}")]
|
||||
@@ -169,8 +173,10 @@ impl ExecuteError {
|
||||
ExecuteError::BadRequest(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::Read(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::ReadExact(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::Seek(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::Write(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::WriteAll(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::Unsupported(_) => VIRTIO_BLK_S_UNSUPP,
|
||||
ExecuteError::SubmitIoUring(_) => VIRTIO_BLK_S_IOERR,
|
||||
ExecuteError::GetHostAddress(_) => VIRTIO_BLK_S_IOERR,
|
||||
@@ -351,13 +357,21 @@ impl Request {
|
||||
|
||||
match self.request_type {
|
||||
RequestType::In => {
|
||||
mem.read_exact_from(*data_addr, disk, *data_len as usize)
|
||||
.map_err(ExecuteError::Read)?;
|
||||
let mut buf = vec![0u8; *data_len as usize];
|
||||
disk.read_exact(&mut buf).map_err(ExecuteError::ReadExact)?;
|
||||
mem.read_exact_volatile_from(
|
||||
*data_addr,
|
||||
&mut buf.as_slice(),
|
||||
*data_len as usize,
|
||||
)
|
||||
.map_err(ExecuteError::Read)?;
|
||||
len += data_len;
|
||||
}
|
||||
RequestType::Out => {
|
||||
mem.write_all_to(*data_addr, disk, *data_len as usize)
|
||||
let mut buf: Vec<u8> = Vec::new();
|
||||
mem.write_all_volatile_to(*data_addr, &mut buf, *data_len as usize)
|
||||
.map_err(ExecuteError::Write)?;
|
||||
disk.write_all(&buf).map_err(ExecuteError::WriteAll)?;
|
||||
if !self.writeback {
|
||||
disk.flush().map_err(ExecuteError::Flush)?;
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ impl<T: Cacheable> CacheMap<T> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
struct NumCache(pub u64);
|
||||
struct NumCache(());
|
||||
impl Cacheable for NumCache {
|
||||
fn dirty(&self) -> bool {
|
||||
true
|
||||
@@ -148,28 +148,28 @@ mod tests {
|
||||
let mut cache = CacheMap::<NumCache>::new(3);
|
||||
let mut evicted = None;
|
||||
cache
|
||||
.insert(0, NumCache(5), |index, _| {
|
||||
.insert(0, NumCache(()), |index, _| {
|
||||
evicted = Some(index);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(evicted, None);
|
||||
cache
|
||||
.insert(1, NumCache(6), |index, _| {
|
||||
.insert(1, NumCache(()), |index, _| {
|
||||
evicted = Some(index);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(evicted, None);
|
||||
cache
|
||||
.insert(2, NumCache(7), |index, _| {
|
||||
.insert(2, NumCache(()), |index, _| {
|
||||
evicted = Some(index);
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(evicted, None);
|
||||
cache
|
||||
.insert(3, NumCache(8), |index, _| {
|
||||
.insert(3, NumCache(()), |index, _| {
|
||||
evicted = Some(index);
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -120,15 +120,20 @@ impl AsyncIo for RawFileAsyncAio {
|
||||
}
|
||||
|
||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||
let iocbs = [&mut aio::IoControlBlock {
|
||||
aio_fildes: self.fd.as_raw_fd() as u32,
|
||||
aio_lio_opcode: aio::IOCB_CMD_FSYNC as u16,
|
||||
aio_data: user_data.unwrap_or(0),
|
||||
aio_flags: aio::IOCB_FLAG_RESFD,
|
||||
aio_resfd: self.eventfd.as_raw_fd() as u32,
|
||||
..Default::default()
|
||||
}];
|
||||
let _ = self.ctx.submit(&iocbs[..]).map_err(AsyncIoError::Fsync)?;
|
||||
if let Some(user_data) = user_data {
|
||||
let iocbs = [&mut aio::IoControlBlock {
|
||||
aio_fildes: self.fd.as_raw_fd() as u32,
|
||||
aio_lio_opcode: aio::IOCB_CMD_FSYNC as u16,
|
||||
aio_data: user_data,
|
||||
aio_flags: aio::IOCB_FLAG_RESFD,
|
||||
aio_resfd: self.eventfd.as_raw_fd() as u32,
|
||||
..Default::default()
|
||||
}];
|
||||
let _ = self.ctx.submit(&iocbs[..]).map_err(AsyncIoError::Fsync)?;
|
||||
} else {
|
||||
// SAFETY: FFI call with a valid fd
|
||||
unsafe { libc::fsync(self.fd) };
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -192,7 +192,9 @@ impl Header {
|
||||
};
|
||||
|
||||
new_header.get_header_as_buffer(&mut buffer);
|
||||
new_header.checksum = crc32c::crc32c(&buffer);
|
||||
let mut crc = crc_any::CRC::crc32c();
|
||||
crc.digest(&buffer);
|
||||
new_header.checksum = crc.get_crc() as u32;
|
||||
new_header.get_header_as_buffer(&mut buffer);
|
||||
|
||||
f.seek(SeekFrom::Start(start))
|
||||
@@ -351,12 +353,6 @@ impl RegionTableEntry {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct RegionEntry {
|
||||
_start: u64,
|
||||
_end: u64,
|
||||
}
|
||||
|
||||
enum HeaderNo {
|
||||
First,
|
||||
Second,
|
||||
@@ -480,7 +476,10 @@ pub fn calculate_checksum(buffer: &mut [u8], csum_offset: usize) -> Result<u32>
|
||||
// Zero the checksum in the buffer
|
||||
LittleEndian::write_u32(csum_buf, 0);
|
||||
// Calculate the checksum on the resulting buffer
|
||||
let new_csum = crc32c::crc32c(buffer);
|
||||
let mut crc = crc_any::CRC::crc32c();
|
||||
crc.digest(&buffer);
|
||||
let new_csum = crc.get_crc() as u32;
|
||||
|
||||
// Put back the original checksum in the buffer
|
||||
LittleEndian::write_u32(&mut buffer[csum_offset..csum_offset + 4], orig_csum);
|
||||
|
||||
|
||||
@@ -6,24 +6,24 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "2.4.1"
|
||||
byteorder = "1.4.3"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
pci = { path = "../pci" }
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.52"
|
||||
tpm = { path = "../tpm" }
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.12.2"
|
||||
vm-memory = "0.14.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
arch = { path = "../arch" }
|
||||
|
||||
64
devices/src/debug_console.rs
Normal file
64
devices/src/debug_console.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright © 2023 Cyberus Technology
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
//! Module for [`DebugconState`].
|
||||
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::sync::{Arc, Barrier};
|
||||
use vm_device::BusDevice;
|
||||
use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
|
||||
|
||||
/// I/O-port.
|
||||
pub const DEFAULT_PORT: u64 = 0xe9;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DebugconState {}
|
||||
|
||||
/// Emulates a debug console similar to the QEMU debugcon device. This device
|
||||
/// is stateless and only prints the bytes (usually text) that are written to
|
||||
/// it.
|
||||
///
|
||||
/// This device is only available on x86.
|
||||
///
|
||||
/// Reference:
|
||||
/// - https://github.com/qemu/qemu/blob/master/hw/char/debugcon.c
|
||||
/// - https://phip1611.de/blog/how-to-use-qemus-debugcon-feature-and-write-to-a-file/
|
||||
pub struct DebugConsole {
|
||||
id: String,
|
||||
out: Box<dyn io::Write + Send>,
|
||||
}
|
||||
|
||||
impl DebugConsole {
|
||||
pub fn new(id: String, out: Box<dyn io::Write + Send>) -> Self {
|
||||
Self { id, out }
|
||||
}
|
||||
}
|
||||
|
||||
impl BusDevice for DebugConsole {
|
||||
fn read(&mut self, _base: u64, _offset: u64, _data: &mut [u8]) {}
|
||||
|
||||
fn write(&mut self, _base: u64, _offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
|
||||
if let Err(e) = self.out.write_all(data) {
|
||||
// unlikely
|
||||
error!("debug-console: failed writing data: {e:?}");
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Snapshottable for DebugConsole {
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> Result<Snapshot, MigratableError> {
|
||||
Snapshot::new_from_state(&())
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for DebugConsole {}
|
||||
impl Transportable for DebugConsole {}
|
||||
impl Migratable for DebugConsole {}
|
||||
@@ -15,6 +15,8 @@ extern crate event_monitor;
|
||||
extern crate log;
|
||||
|
||||
pub mod acpi;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub mod debug_console;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub mod gic;
|
||||
pub mod interrupt_controller;
|
||||
|
||||
@@ -26,6 +26,7 @@ const PVPANIC_VENDOR_ID: u16 = 0x1b36;
|
||||
const PVPANIC_DEVICE_ID: u16 = 0x0011;
|
||||
|
||||
pub const PVPANIC_DEVICE_MMIO_SIZE: u64 = 0x2;
|
||||
pub const PVPANIC_DEVICE_MMIO_ALIGNMENT: u64 = 0x10;
|
||||
|
||||
const PVPANIC_PANICKED: u8 = 1 << 0;
|
||||
const PVPANIC_CRASH_LOADED: u8 = 1 << 1;
|
||||
@@ -180,8 +181,9 @@ impl PciDevice for PvPanicDevice {
|
||||
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
_mmio_allocator: &mut AddressAllocator,
|
||||
_allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
_mmio64_allocator: &mut AddressAllocator,
|
||||
resources: Option<Vec<Resource>>,
|
||||
) -> std::result::Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||
let mut bars = Vec::new();
|
||||
@@ -189,10 +191,8 @@ impl PciDevice for PvPanicDevice {
|
||||
let bar_id = 0;
|
||||
let region_size = PVPANIC_DEVICE_MMIO_SIZE;
|
||||
let restoring = resources.is_some();
|
||||
let bar_addr = allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_mmio_hole_addresses(None, region_size, None)
|
||||
let bar_addr = mmio32_allocator
|
||||
.allocate(None, region_size, Some(PVPANIC_DEVICE_MMIO_ALIGNMENT))
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
||||
|
||||
let bar = PciBarConfiguration::default()
|
||||
@@ -217,11 +217,12 @@ impl PciDevice for PvPanicDevice {
|
||||
|
||||
fn free_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
_mmio_allocator: &mut AddressAllocator,
|
||||
_allocator: &mut SystemAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
_mmio64_allocator: &mut AddressAllocator,
|
||||
) -> std::result::Result<(), PciDeviceError> {
|
||||
for bar in self.bar_regions.drain(..) {
|
||||
allocator.free_mmio_hole_addresses(GuestAddress(bar.addr()), bar.size());
|
||||
mmio32_allocator.free(GuestAddress(bar.addr()), bar.size());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -36,3 +36,5 @@ You can run a SEV-SNP VM using the following command:
|
||||
--memory size=1G \
|
||||
--disk path=ubuntu.img
|
||||
```
|
||||
|
||||
For more information related to Microsoft Hypervisor please see [mshv.md](mshv.md)
|
||||
|
||||
12
docs/api.md
12
docs/api.md
@@ -147,7 +147,7 @@ We want to create a virtual machine with the following characteristics:
|
||||
`/opt/clh/images/focal-server-cloudimg-amd64.raw`
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-X PUT 'http://localhost/api/v1/vm.create' \
|
||||
@@ -167,7 +167,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
Once the VM is created, we can boot it:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
||||
```
|
||||
@@ -177,7 +177,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
|
||||
We can fetch information about any VM, as soon as it's created:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-X GET 'http://localhost/api/v1/vm.info' \
|
||||
@@ -189,7 +189,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
We can reboot a VM that's already booted:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
||||
```
|
||||
@@ -199,7 +199,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1
|
||||
Once booted, we can shut a VM down from the REST API:
|
||||
|
||||
```shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
||||
```
|
||||
@@ -385,7 +385,7 @@ APIs work together, let's look at a complete VM creation flow, from the
|
||||
[REST API](#rest-api) in order to creates a virtual machine:
|
||||
```
|
||||
shell
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-X PUT 'http://localhost/api/v1/vm.create' \
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
# `cloud-hypervisor` debug IO port
|
||||
# `cloud-hypervisor` debug IO ports
|
||||
|
||||
`cloud-hypervisor` uses the [`0x80`](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
|
||||
I/O port to trace user defined guest events.
|
||||
When running x86 guests, `cloud-hypervisor` provides different kinds of debug ports:
|
||||
- [`0x80` debug port](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
|
||||
- Debug console (by default at `0xe9`).
|
||||
- Firmware debug port at `0x402`.
|
||||
|
||||
All of them can be used to trace user-defined guest events and all of them can
|
||||
be used simultaneously.
|
||||
|
||||
## Debug Ports Overview
|
||||
|
||||
### `0x80` I/O port
|
||||
|
||||
Whenever the guest write one byte between `0x0` and `0xF` on this particular
|
||||
I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug`
|
||||
@@ -30,7 +39,7 @@ guest will have `cloud-hypervisor` generate timestamped logs of all those steps.
|
||||
That provides a basic but convenient way of measuring not only the overall guest
|
||||
boot time but all intermediate steps as well.
|
||||
|
||||
## Logging
|
||||
#### Logging
|
||||
|
||||
Assuming parts of the guest software stack have been instrumented to use the
|
||||
`cloud-hypervisor` debug I/O port, we may want to gather the related logs.
|
||||
@@ -59,3 +68,29 @@ $ grep "Debug I/O port" /tmp/ch-fw.log
|
||||
cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds
|
||||
cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds
|
||||
```
|
||||
|
||||
### Debug console port
|
||||
|
||||
The debug console is inspired by QEMU and Bochs, which have a similar feature.
|
||||
By default, the I/O port `0xe9` is used. This port can be configured like a
|
||||
console. Thus, it can print to a tty, a file, or a pty, for example.
|
||||
|
||||
### Firmware debug port
|
||||
|
||||
The firmware debug port is also a simple port that prints all bytes written to
|
||||
it. The firmware debug port only prints to stdout.
|
||||
|
||||
## When do I need these ports?
|
||||
|
||||
The ports are on the one hand interesting for firmware or kernel developers, as
|
||||
they provide an easy way to print debug information from within a guest.
|
||||
Furthermore, you can patch "normal" software to measure certain events, such as
|
||||
the boot time of a guest.
|
||||
|
||||
## Which port should I choose?
|
||||
|
||||
The `0x80` debug port and the port of the firmware debug device are always
|
||||
available. The debug console must be activated via the command line, but
|
||||
provides more configuration options.
|
||||
|
||||
You can use different ports for different aspect of your logging messages.
|
||||
@@ -103,7 +103,7 @@ firmware:
|
||||
### TDShim
|
||||
|
||||
> **Note**
|
||||
> The latest version of TDShim being tested is [_66bb334_](https://github.com/confidential-containers/td-shim/tree/66bb33451befbf1291abe3cfea7ee9e99d922b0d).
|
||||
> The latest version of TDShim being tested is [_v0.8.0_](https://github.com/confidential-containers/td-shim/releases/tag/v0.8.0).
|
||||
|
||||
This is a lightweight version of the TDVF, written in Rust and designed for
|
||||
direct kernel boot, which is useful for containers use cases.
|
||||
@@ -113,7 +113,7 @@ and `LLVM` first. The TDshim can be build as follows:
|
||||
```bash
|
||||
git clone https://github.com/confidential-containers/td-shim
|
||||
cd td-shim
|
||||
git checkout 66bb33451befbf1291abe3cfea7ee9e99d922b0d
|
||||
git checkout v0.8.0
|
||||
cargo install cargo-xbuild
|
||||
export CC=clang
|
||||
export AR=llvm-ar
|
||||
@@ -121,15 +121,13 @@ export CC_x86_64_unknown_none=clang
|
||||
export AR_x86_64_unknown_none=llvm-ar
|
||||
git submodule update --init --recursive
|
||||
./sh_script/preparation.sh
|
||||
cargo xbuild -p td-shim --target x86_64-unknown-none --release --features=main,tdx
|
||||
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/release/ResetVector.bin target/x86_64-unknown-none/release/td-shim -o target/release/final.bin
|
||||
cargo image --release
|
||||
```
|
||||
|
||||
If debug logs from the TDShim is needed, here are the alternative
|
||||
commands:
|
||||
```bash
|
||||
cargo xbuild -p td-shim --target x86_64-unknown-none --features=main,tdx
|
||||
cargo run -p td-shim-tools --bin td-shim-ld --features=linker -- target/x86_64-unknown-none/debug/ResetVector.bin target/x86_64-unknown-none/debug/td-shim -o target/debug/final.bin
|
||||
cargo image
|
||||
```
|
||||
|
||||
And run a TDX VM by providing the firmware previously built, along with a guest
|
||||
|
||||
@@ -42,3 +42,14 @@ actual rate limit users get can be as low as
|
||||
generally advisable to keep `bw/ops_refill_time` larger than `100 ms`
|
||||
(`cool_down_time`) to make sure the actual rate limit is close to users'
|
||||
expectation ("refill-rate").
|
||||
|
||||
## Rate Limit Groups
|
||||
It is possible to throttle the aggregate bandwidth or operations
|
||||
of multiple virtio-blk devices using a `rate_limit_group`. virtio-blk devices may be
|
||||
dynamically added and removed from a `rate_limit_group`. The following example
|
||||
demonstrates how to throttle the aggregate bandwidth of two disks to 10 MiB/s.
|
||||
```
|
||||
--disk path=disk0.raw,rate_limit_group=group0 \
|
||||
path=disk1.raw,rate_limit_group=group0 \
|
||||
--rate-limit-group bw_size=1048576,bw_refill_time,bw_refill_time=100
|
||||
```
|
||||
|
||||
@@ -60,10 +60,7 @@ implement a full emulation of a physical IOMMU.
|
||||
|
||||
### Kernel
|
||||
|
||||
Since virtio-iommu has landed partially into the version 5.3 of the Linux
|
||||
kernel, a special branch is needed to get things working with Cloud Hypervisor.
|
||||
By partially, we are talking about x86 specifically, as it is already fully
|
||||
functional for ARM architectures.
|
||||
As of Kernel 5.14, virtio-iommu is available for both X86-64 and Aarch64.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
48
docs/mshv.md
Normal file
48
docs/mshv.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Microsoft Hypervisor
|
||||
|
||||
The Microsoft Hypervisor is a Type 1 hypervisor which runs on x64 and ARM64 architectures. As the foundation of the Hyper-V virtualization stack, it runs millions of Linux and Windows guests in Azure and on-premises deployments. It supports nested virtualization, and security features like AMD's SEV-SNP. It also supports various features in Windows such as [Device guard and confidential guard](https://techcommunity.microsoft.com/t5/iis-support-blog/windows-10-device-guard-and-credential-guard-demystified/ba-p/376419), and [WSL2](https://docs.microsoft.com/en-us/windows/wsl/wsl2-faq)
|
||||
|
||||
Since 2020, Microsoft has been releasing open-source components to support Linux running as root partition on the Microsoft Hypervisor.
|
||||
|
||||
1. Kernel patches to support Linux booting as root partition
|
||||
2. A Linux kernel driver exposing an IOCTL interface for managing guest partitions, via a device node - /dev/mshv
|
||||
3. Rust bindings and IOCTL wrappers
|
||||
4. IGVM related crates
|
||||
|
||||
## Components
|
||||
|
||||
The following components are related to MSHV support with Cloud-Hypervisor:
|
||||
|
||||
* [igvm-crates](https://github.com/microsoft/igvm) : Parsing IGVM file
|
||||
|
||||
* [mshv-crates](https://github.com/rust-vmm/mshv) : Rust crates to interact with kernel module (/dev/mshv)
|
||||
|
||||
* [igvm-tooling](https://github.com/microsoft/igvm-tooling) : Tool to generate IGVM file
|
||||
|
||||
## IGVM
|
||||
|
||||
Independent Guest Virtual Machine (IGVM) file format.The format specification can be found in the igvm_defs crate, with a Rust implementation of the binary format in the igvm crate.
|
||||
|
||||
The IGVM file format is designed to encapsulate all information required to launch a virtual machine on any given virtualization stack, with support for different isolation technologies such as AMD SEV-SNP and Intel TDX.
|
||||
|
||||
At a conceptual level, this file format is a set of commands created by the tool that generated the file, used by the loader to construct the initial guest state. The file format also contains measurement information that the underlying platform will use to confirm that the file was loaded correctly and signed by the appropriate authorities.
|
||||
|
||||
Cloud Hypervisor can be built using igvm feature flag along with mshv and/or sev-snp. IGVM only works with MSHV.
|
||||
|
||||
## SEV-SNP
|
||||
|
||||
AMD's [Secure Encrypted Virtualization (SEV)](https://www.amd.com/en/developer/sev.html) and extensions such as Secure Nested Paging (SEV-SNP) encrypt memory and restrict access to a guest VM's memory and registers, securing it against a compromised hypervisor or VMM. They utilize the Platform Security Processor (PSP) to store keys and encrypt/decrypt the data. Microsoft has been continuously adding/improving support for SEV-SNP on Microsoft Hyper-V. Cloud-Hypervisor can be built with the sev_snp feature including mshv and igvm feature.
|
||||
|
||||
## Use Cases
|
||||
|
||||
Cloud Hypervisor can be built to run on an MSHV root partition by enabling the mshv feature, e.g.:
|
||||
|
||||
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features mshv```
|
||||
|
||||
Cloud Hypervisor on MSHV can boot Linux guests using an IGVM file. IGVM feature depends on mshv for running legacy VMs.e.g.:
|
||||
|
||||
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features igvm```
|
||||
|
||||
For running confidential VMs on mshv, you will only need to enable sev_snp, it requires and enables mshv and igvm automatically, eg.:
|
||||
|
||||
```cargo build --locked --all --all-targets --no-default-features --tests --examples --features sev_snp```
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
The purpose of this document is to illustrate how to test vhost-user-net
|
||||
in cloud-hypervisor with OVS/DPDK as the backend. This document was
|
||||
tested with Open vSwitch v2.13.1, DPDK v19.11.3, and Cloud Hypervisor
|
||||
v15.0 on Ubuntu 20.04.1 (host kernel v5.4.0).
|
||||
tested with Open vSwitch v2.17.8, DPDK v21.11.4, and Cloud Hypervisor
|
||||
v37.0 on Ubuntu 22.04.3 (host kernel v5.15.0).
|
||||
|
||||
## Framework
|
||||
|
||||
@@ -74,8 +74,8 @@ Here is an example how to create a bridge and add two DPDK ports to it
|
||||
# create a bridge
|
||||
ovs-vsctl add-br ovsbr0 -- set bridge ovsbr0 datapath_type=netdev
|
||||
# create two DPDK ports and add them to the bridge
|
||||
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuser
|
||||
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuser
|
||||
ovs-vsctl add-port ovsbr0 vhost-user1 -- set Interface vhost-user1 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user1
|
||||
ovs-vsctl add-port ovsbr0 vhost-user2 -- set Interface vhost-user2 type=dpdkvhostuserclient options:vhost-server-path=/tmp/vhost-user2
|
||||
# set the number of rx queues
|
||||
ovs-vsctl set Interface vhost-user1 options:n_rxq=2
|
||||
ovs-vsctl set Interface vhost-user2 options:n_rxq=2
|
||||
@@ -92,7 +92,7 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
||||
--kernel vmlinux \
|
||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--net mac=52:54:00:02:d9:01,vhost_user=true,socket=/var/run/openvswitch/vhost-user1,num_queues=4
|
||||
--net mac=52:54:00:02:d9:01,vhost_user=true,socket=/tmp/vhost-user1,num_queues=4,vhost_mode=server
|
||||
|
||||
# From another terminal. We need to give the cloud-hypervisor binary the NET_ADMIN capabilities for it to set TAP interfaces up on the host.
|
||||
./cloud-hypervisor \
|
||||
@@ -101,21 +101,21 @@ VMs run in client mode. They connect to the socket created by the `dpdkvhostuser
|
||||
--kernel vmlinux \
|
||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
||||
--disk path=focal-server-cloudimg-amd64.raw \
|
||||
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/var/run/openvswitch/vhost-user2,num_queues=4
|
||||
--net mac=52:54:20:11:C5:02,vhost_user=true,socket=/tmp/vhost-user2,num_queues=4,vhost_mode=server
|
||||
```
|
||||
|
||||
_Setup VM1_
|
||||
```bash
|
||||
# From inside the guest
|
||||
sudo ip addr add 172.100.0.1/24 dev ens2
|
||||
sudo ip link set up dev ens2
|
||||
sudo ip addr add 172.100.0.1/24 dev ens3
|
||||
sudo ip link set up dev ens3
|
||||
```
|
||||
|
||||
_Setup VM2_
|
||||
```bash
|
||||
# From inside the guest
|
||||
sudo ip addr add 172.100.0.2/24 dev ens2
|
||||
sudo ip link set up dev ens2
|
||||
sudo ip addr add 172.100.0.2/24 dev ens3
|
||||
sudo ip link set up dev ens3
|
||||
```
|
||||
|
||||
_Ping VM1 from VM2_
|
||||
|
||||
@@ -49,7 +49,7 @@ qemu-system-x86_64 \
|
||||
-m 4G \
|
||||
-bios ./$OVMF_DIR/OVMF_CODE.fd \
|
||||
-cdrom ./$WIN_ISO_FILE \
|
||||
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom
|
||||
-drive file=./$VIRTIO_ISO_FILE,index=0,media=cdrom \
|
||||
-drive if=none,id=root,file=./$IMG_FILE \
|
||||
-device virtio-blk-pci,drive=root,disable-legacy=on \
|
||||
-device virtio-net-pci,netdev=mynet0,disable-legacy=on \
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
flume = "0.10.14"
|
||||
libc = "0.2.147"
|
||||
once_cell = "1.18.0"
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.107"
|
||||
libc = "0.2.153"
|
||||
once_cell = "1.19.0"
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.109"
|
||||
|
||||
330
fuzz/Cargo.lock
generated
330
fuzz/Cargo.lock
generated
@@ -12,9 +12,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.4"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
@@ -26,33 +26,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.4"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.2"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
|
||||
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.0.0"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
||||
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.1"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
|
||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
@@ -60,9 +60,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -73,9 +73,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.3.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2e1373abdaa212b704512ec2bd8b26bd0b7d5c3f70117411a5d9a451383c859"
|
||||
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
@@ -137,7 +137,7 @@ name = "block"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"crc32c",
|
||||
"crc-any",
|
||||
"io-uring",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -184,34 +184,34 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.7"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
|
||||
checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.7"
|
||||
version = "4.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
|
||||
checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
"strsim 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "35.0.0"
|
||||
version = "37.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -252,6 +252,7 @@ dependencies = [
|
||||
"virtio-queue",
|
||||
"vm-device",
|
||||
"vm-memory",
|
||||
"vm-migration",
|
||||
"vm-virtio",
|
||||
"vmm",
|
||||
"vmm-sys-util",
|
||||
@@ -264,25 +265,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "crc32c"
|
||||
version = "0.6.4"
|
||||
name = "crc-any"
|
||||
version = "2.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8f48d60e5b4d2c53d5c2b1d8a58c849a70ae5e5509b08a48d047e3b65714a74"
|
||||
checksum = "c01a5e1f881f6fb6099a7bdf949e946719fd4f1fefa56264890574febf0eb6d0"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
"debug-helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc64"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
checksum = "2707e3afba5e19b75d582d88bc79237418f2a2a2d673d01cf9b03633b46e98f3"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||
checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -290,29 +291,35 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||
checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.32",
|
||||
"strsim 0.10.0",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.3"
|
||||
version = "0.20.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||
checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "debug-helper"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
|
||||
|
||||
[[package]]
|
||||
name = "devices"
|
||||
version = "0.1.0"
|
||||
@@ -386,21 +393,21 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.29"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
|
||||
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.28"
|
||||
version = "0.3.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
|
||||
checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -435,9 +442,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "io-uring"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "460648e47a07a43110fbfa2e0b14afb2be920093c31e5dccc50e49568e099762"
|
||||
checksum = "a9febecd4aebbe9c7c23c8e536e966805fdf09944c8a915e7991ee51acb67087"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
@@ -445,32 +452,32 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.27"
|
||||
version = "0.1.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
|
||||
checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.64"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kvm-bindings"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.6.0-tdx#7d9ffb47e5b9b1989577258800a0f57c93f1445f"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.7.0#2dcf85d4f8aa55befcaa996b699ddb18ec9ed059"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -479,10 +486,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kvm-ioctls"
|
||||
version = "0.13.0"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8f8dc9c1896e5f144ec5d07169bc29f39a047686d29585a91f30489abfaeb6b"
|
||||
checksum = "9002dff009755414f22b962ec6ae6980b07d6d8b06e5297b1062019d72bd6a8c"
|
||||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"kvm-bindings",
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -490,9 +498,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.153"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -507,9 +515,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.9.1"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1db6a725c8000971f83fa93ed7ee1b600e55a1471a2a653379d3c84f72effdcf"
|
||||
checksum = "eb68dd3452f25a8defaf0ae593509cff0c777683e4d8924f59ac7c5f89267a83"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
@@ -533,7 +541,7 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#a4d632f2c5ea45712c0d2002dc909a63879e85c3"
|
||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#e75dfa1eeea23b69caa7407bc2c3a76d7b7262fb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"vmm-sys-util",
|
||||
@@ -578,9 +586,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
@@ -611,38 +619,38 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
|
||||
checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.69"
|
||||
version = "1.0.78"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
||||
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
version = "1.0.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -651,36 +659,29 @@ dependencies = [
|
||||
name = "rate_limiter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"epoll",
|
||||
"libc",
|
||||
"log",
|
||||
"thiserror",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remain"
|
||||
version = "0.2.11"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bce3a7139d2ee67d07538ee5dba997364fbc243e7e7143e96eb830c74bfaa082"
|
||||
checksum = "1ad5e011230cad274d0532460c5ab69828ea47ae75681b42a841663efffaf794"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
version = "1.0.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
@@ -697,37 +698,31 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.189"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
|
||||
checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.189"
|
||||
version = "1.0.196"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
|
||||
checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.108"
|
||||
version = "1.0.113"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
|
||||
checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -753,7 +748,7 @@ dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -781,9 +776,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.1"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
@@ -800,6 +795,12 @@ version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -813,9 +814,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.32"
|
||||
version = "2.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
|
||||
checksum = "1726efe18f42ae774cc644f330953a5e7b3c3003d3edcecf18850fe9d4dd9afb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -824,22 +825,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.50"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
|
||||
checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.50"
|
||||
version = "1.0.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
|
||||
checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -880,18 +881,18 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.5.0"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc"
|
||||
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.10"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
|
||||
checksum = "62929d59c7f6730b7298fcb363760550f4db6e353fbac4076d447d0e82799d6d"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crc64",
|
||||
@@ -906,8 +907,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "versionize_derive"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6"
|
||||
version = "0.1.6"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch-0.1.6#7906da996152e2d0ab08f5526440683bf3ca7834"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -917,7 +918,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#847b0aa504ac6367efe42ba7e96a2d050737d4f0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -925,7 +926,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#847b0aa504ac6367efe42ba7e96a2d050737d4f0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#0daff4d4c159e842cf18b8b90457a45032b2df5a"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -941,7 +942,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#2d96b90a7279547356ad8f83aaa3115ad5497302"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#a1f6e52829e069b6d698b2cfeecac742e4653186"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
@@ -957,11 +958,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.8.1"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61957aeb36daf0b00b87fff9c10dd28a161bd35ab157553d340d183b3d8756e6"
|
||||
checksum = "2b64e816d0d49769fbfaa1494eb77cc2a3ddc526ead05c7f922cb7d64106286f"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.4.1",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
@@ -969,9 +970,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c18d7b74098a946470ea265b5bacbbf877abc3373021388454de0d47735a5b98"
|
||||
checksum = "878bcb1b2812a10c30d53b0ed054999de3d98f25ece91fc173973f9c57aaae86"
|
||||
|
||||
[[package]]
|
||||
name = "virtio-devices"
|
||||
@@ -1009,9 +1010,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-queue"
|
||||
version = "0.9.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35aca00da06841bd99162c381ec65893cace23ca0fb89254302cfe4bec4c300f"
|
||||
checksum = "e3f69a13d6610db9312acbb438b0390362af905d37634a2106be70c0f734986d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"virtio-bindings",
|
||||
@@ -1048,9 +1049,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.12.2"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dc276f0d00c17b9aeb584da0f1e1c673df0d183cc2539e3636ec8cbc5eae99b"
|
||||
checksum = "74ffc42216c32c35f858fa4bfdcd9b61017dfd691e0240268fdc85dbf59e5459"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -1105,6 +1106,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"option_parser",
|
||||
"pci",
|
||||
"rate_limiter",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -1130,9 +1132,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vmm-sys-util"
|
||||
version = "0.11.2"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48b7b084231214f7427041e4220d77dfe726897a6d41fddee450696e66ff2a29"
|
||||
checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
@@ -1148,9 +1150,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.87"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -1158,24 +1160,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.87"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -1183,22 +1185,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.87"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.87"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
@@ -1224,18 +1226,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
@@ -1248,51 +1250,51 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.48.5"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.20"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd66a62464e3ffd4e37bd09950c2b9dd6c4f8767380fabba0d523f9a775bc85a"
|
||||
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
@@ -1300,11 +1302,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.20"
|
||||
version = "0.7.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "255c4596d41e6916ced49cfafea18727b24d67878fa180ddfd69b9df34fd1726"
|
||||
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.32",
|
||||
"syn 2.0.47",
|
||||
]
|
||||
|
||||
@@ -8,22 +8,26 @@ edition = "2021"
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
[features]
|
||||
igvm = []
|
||||
|
||||
[dependencies]
|
||||
block = { path = "../block" }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.149"
|
||||
libc = "0.2.152"
|
||||
libfuzzer-sys = "0.4.7"
|
||||
linux-loader = { version = "0.9.1", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.11.0", features = ["elf", "bzimage", "pe"] }
|
||||
micro_http = { git = "https://github.com/firecracker-microvm/micro-http", branch = "main" }
|
||||
net_util = { path = "../net_util" }
|
||||
once_cell = "1.18.0"
|
||||
once_cell = "1.19.0"
|
||||
seccompiler = "0.4.0"
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.9.0"
|
||||
virtio-queue = "0.11.0"
|
||||
vmm = { path = "../vmm" }
|
||||
vmm-sys-util = "0.11.2"
|
||||
vm-memory = "0.12.2"
|
||||
vmm-sys-util = "0.12.1"
|
||||
vm-memory = "0.14.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
|
||||
@@ -31,8 +35,8 @@ vm-virtio = { path = "../vm-virtio" }
|
||||
path = ".."
|
||||
|
||||
[patch.crates-io]
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.7.0" }
|
||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch-0.1.6" }
|
||||
|
||||
# Prevent this from interfering with workspaces
|
||||
[workspace]
|
||||
|
||||
@@ -21,6 +21,7 @@ use virtio_devices::{Block, VirtioDevice, VirtioInterrupt, VirtioInterruptType};
|
||||
use virtio_queue::{Queue, QueueT};
|
||||
use vm_memory::{bitmap::AtomicBitmap, Bytes, GuestAddress, GuestMemoryAtomic};
|
||||
use vmm_sys_util::eventfd::{EventFd, EFD_NONBLOCK};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||
|
||||
@@ -49,6 +50,7 @@ fuzz_target!(|bytes| {
|
||||
let shm = memfd_create(&ffi::CString::new("fuzz").unwrap(), 0).unwrap();
|
||||
let disk_file: File = unsafe { File::from_raw_fd(shm) };
|
||||
let qcow_disk = Box::new(RawFileDiskSync::new(disk_file)) as Box<dyn DiskFile>;
|
||||
let queue_affinity = BTreeMap::new();
|
||||
let mut block = Block::new(
|
||||
"tmp".to_owned(),
|
||||
qcow_disk,
|
||||
@@ -62,6 +64,7 @@ fuzz_target!(|bytes| {
|
||||
None,
|
||||
EventFd::new(EFD_NONBLOCK).unwrap(),
|
||||
None,
|
||||
queue_affinity,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
use devices::legacy::Cmos;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use vm_device::BusDevice;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
|
||||
@@ -7,9 +7,18 @@ use libfuzzer_sys::fuzz_target;
|
||||
use micro_http::Request;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{channel, Receiver};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use vmm::api::{http::*, ApiRequest, ApiResponsePayload};
|
||||
use vm_migration::MigratableError;
|
||||
use vmm::api::{
|
||||
http::*, ApiRequest, RequestHandler, VmInfoResponse, VmReceiveMigrationData,
|
||||
VmSendMigrationData, VmmPingResponse,
|
||||
};
|
||||
use vmm::config::RestoreConfig;
|
||||
use vmm::vm::{Error as VmError, VmState};
|
||||
use vmm::vm_config::*;
|
||||
use vmm::{EpollContext, EpollDispatch};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
@@ -69,6 +78,203 @@ fn generate_request(bytes: &[u8]) -> Option<Request> {
|
||||
Request::try_from(&request, None).ok()
|
||||
}
|
||||
|
||||
struct StubApiRequestHandler;
|
||||
|
||||
impl RequestHandler for StubApiRequestHandler {
|
||||
fn vm_create(&mut self, _: Arc<Mutex<VmConfig>>) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_boot(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_pause(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_resume(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_snapshot(&mut self, _: &str) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_restore(&mut self, _: RestoreConfig) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
fn vm_coredump(&mut self, _: &str) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_shutdown(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_reboot(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_info(&self) -> Result<VmInfoResponse, VmError> {
|
||||
Ok(VmInfoResponse {
|
||||
config: Arc::new(Mutex::new(VmConfig {
|
||||
cpus: CpusConfig {
|
||||
boot_vcpus: 1,
|
||||
max_vcpus: 1,
|
||||
topology: None,
|
||||
kvm_hyperv: false,
|
||||
max_phys_bits: 46,
|
||||
affinity: None,
|
||||
features: CpuFeatures::default(),
|
||||
},
|
||||
memory: MemoryConfig {
|
||||
size: 536_870_912,
|
||||
mergeable: false,
|
||||
hotplug_method: HotplugMethod::Acpi,
|
||||
hotplug_size: None,
|
||||
hotplugged_size: None,
|
||||
shared: false,
|
||||
hugepages: false,
|
||||
hugepage_size: None,
|
||||
prefault: false,
|
||||
zones: None,
|
||||
thp: true,
|
||||
},
|
||||
payload: Some(PayloadConfig {
|
||||
kernel: Some(PathBuf::from("/path/to/kernel")),
|
||||
firmware: None,
|
||||
cmdline: None,
|
||||
initramfs: None,
|
||||
#[cfg(feature = "igvm")]
|
||||
igvm: None,
|
||||
}),
|
||||
rate_limit_groups: None,
|
||||
disks: None,
|
||||
net: None,
|
||||
rng: RngConfig {
|
||||
src: PathBuf::from("/dev/urandom"),
|
||||
iommu: false,
|
||||
},
|
||||
balloon: None,
|
||||
fs: None,
|
||||
pmem: None,
|
||||
serial: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Null,
|
||||
iommu: false,
|
||||
socket: None,
|
||||
},
|
||||
console: ConsoleConfig {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Tty,
|
||||
iommu: false,
|
||||
socket: None,
|
||||
},
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
debug_console: DebugConsoleConfig::default(),
|
||||
devices: None,
|
||||
user_devices: None,
|
||||
vdpa: None,
|
||||
vsock: None,
|
||||
pvpanic: false,
|
||||
iommu: false,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
sgx_epc: None,
|
||||
numa: None,
|
||||
watchdog: false,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
gdb: false,
|
||||
platform: None,
|
||||
tpm: None,
|
||||
preserved_fds: None,
|
||||
})),
|
||||
state: VmState::Running,
|
||||
memory_actual_size: 0,
|
||||
device_tree: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn vmm_ping(&self) -> VmmPingResponse {
|
||||
VmmPingResponse {
|
||||
build_version: String::new(),
|
||||
version: String::new(),
|
||||
pid: 0,
|
||||
features: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn vm_delete(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vmm_shutdown(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_resize(&mut self, _: Option<u8>, _: Option<u64>, _: Option<u64>) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_resize_zone(&mut self, _: String, _: u64) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_add_device(&mut self, _: DeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_user_device(&mut self, _: UserDeviceConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_remove_device(&mut self, _: String) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_add_disk(&mut self, _: DiskConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_fs(&mut self, _: FsConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_pmem(&mut self, _: PmemConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_net(&mut self, _: NetConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_vdpa(&mut self, _: VdpaConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_add_vsock(&mut self, _: VsockConfig) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_counters(&mut self) -> Result<Option<Vec<u8>>, VmError> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn vm_power_button(&mut self) -> Result<(), VmError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_receive_migration(&mut self, _: VmReceiveMigrationData) -> Result<(), MigratableError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vm_send_migration(&mut self, _: VmSendMigrationData) -> Result<(), MigratableError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receiver<ApiRequest>) {
|
||||
let mut epoll = EpollContext::new().unwrap();
|
||||
epoll.add_event(&exit_evt, EpollDispatch::Exit).unwrap();
|
||||
@@ -98,89 +304,7 @@ fn http_receiver_stub(exit_evt: EventFd, api_evt: EventFd, api_receiver: Receive
|
||||
EpollDispatch::Api => {
|
||||
for _ in 0..api_evt.read().unwrap() {
|
||||
let api_request = api_receiver.recv().unwrap();
|
||||
match api_request {
|
||||
ApiRequest::VmCreate(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmDelete(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmBoot(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmShutdown(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmReboot(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmInfo(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmmPing(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmPause(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmResume(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmSnapshot(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmRestore(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmmShutdown(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmResize(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmResizeZone(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddDevice(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddUserDevice(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmRemoveDevice(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddDisk(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddFs(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddPmem(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddNet(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddVdpa(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmAddVsock(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmCounters(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmReceiveMigration(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmSendMigration(_, sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
ApiRequest::VmPowerButton(sender) => {
|
||||
sender.send(Ok(ApiResponsePayload::Empty)).unwrap();
|
||||
}
|
||||
}
|
||||
api_request(&mut StubApiRequestHandler).unwrap();
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
||||
@@ -23,6 +23,8 @@ fuzz_target!(|bytes| {
|
||||
kernel: None,
|
||||
cmdline: Some(String::from_utf8_lossy(&bytes).to_string()),
|
||||
initramfs: None,
|
||||
#[cfg(feature = "igvm")]
|
||||
igvm: None,
|
||||
};
|
||||
let kernel_cmdline = match vmm::vm::Vm::generate_cmdline(&payload_config) {
|
||||
Ok(cmdline) => cmdline,
|
||||
|
||||
@@ -12,22 +12,22 @@ sev_snp = ["igvm_parser", "igvm_defs"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
byteorder = "1.4.3"
|
||||
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main" , package = "igvm_defs", optional = true }
|
||||
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main" , package = "igvm", optional = true }
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
igvm_defs = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm_defs", optional = true }
|
||||
igvm_parser = { git = "https://github.com/microsoft/igvm", branch = "main", package = "igvm", optional = true }
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
kvm-ioctls = { version = "0.16.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.7.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
serde_with = { version = "3.4.0", default-features = false, features = ["macros"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
thiserror = "1.0.40"
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.12.1", features = ["with-serde"] }
|
||||
thiserror = "1.0.52"
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
optional = true
|
||||
@@ -36,4 +36,4 @@ default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = "0.10.0"
|
||||
env_logger = "0.10.1"
|
||||
|
||||
@@ -311,3 +311,17 @@ pub struct MsrEntry {
|
||||
pub index: u32,
|
||||
pub data: u64,
|
||||
}
|
||||
|
||||
#[serde_with::serde_as]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
||||
pub struct XsaveState {
|
||||
#[serde_as(as = "[_; 1024usize]")]
|
||||
pub region: [u32; 1024usize],
|
||||
}
|
||||
|
||||
impl Default for XsaveState {
|
||||
fn default() -> Self {
|
||||
// SAFETY: this is plain old data structure
|
||||
unsafe { ::std::mem::zeroed() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,12 +95,12 @@ pub enum HypervisorCpuError {
|
||||
#[error("Failed to get Msr entries: {0}")]
|
||||
GetMsrEntries(#[source] anyhow::Error),
|
||||
///
|
||||
/// Setting MSR entries error
|
||||
/// Setting multi-processing state error
|
||||
///
|
||||
#[error("Failed to set MP state: {0}")]
|
||||
SetMpState(#[source] anyhow::Error),
|
||||
///
|
||||
/// Getting Msr entries error
|
||||
/// Getting multi-processing state error
|
||||
///
|
||||
#[error("Failed to get MP state: {0}")]
|
||||
GetMpState(#[source] anyhow::Error),
|
||||
@@ -267,6 +267,17 @@ pub enum HypervisorCpuError {
|
||||
///
|
||||
#[error("Failed to write to GPA: {0}")]
|
||||
GpaWrite(#[source] anyhow::Error),
|
||||
///
|
||||
/// Error getting CPUID leaf
|
||||
///
|
||||
#[error("Failed to get CPUID entries: {0}")]
|
||||
GetCpuidVales(#[source] anyhow::Error),
|
||||
///
|
||||
/// Setting SEV control register error
|
||||
///
|
||||
#[cfg(feature = "sev_snp")]
|
||||
#[error("Failed to set sev control register: {0}")]
|
||||
SetSevControlRegister(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -477,4 +488,21 @@ pub trait Vcpu: Send + Sync {
|
||||
fn set_tsc_khz(&self, _freq: u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to retrieve cpuid leaf
|
||||
///
|
||||
fn get_cpuid_values(
|
||||
&self,
|
||||
_function: u32,
|
||||
_index: u32,
|
||||
_xfem: u64,
|
||||
_xss: u64,
|
||||
) -> Result<[u32; 4]> {
|
||||
unimplemented!()
|
||||
}
|
||||
#[cfg(feature = "mshv")]
|
||||
fn set_sev_control_register(&self, _reg: u64) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
pub mod x86_64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::{
|
||||
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters,
|
||||
CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters, XsaveState,
|
||||
NUM_IOAPIC_PINS,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -66,13 +66,11 @@ use kvm_bindings::{
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use x86_64::check_required_kvm_extensions;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState, Xsave};
|
||||
pub use x86_64::{CpuId, ExtendedControlRegisters, MsrEntries, VcpuKvmState};
|
||||
// aarch64 dependencies
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub mod aarch64;
|
||||
pub use kvm_bindings;
|
||||
#[cfg(feature = "tdx")]
|
||||
use kvm_bindings::KVMIO;
|
||||
pub use kvm_bindings::{
|
||||
kvm_clock_data, kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_guest_debug,
|
||||
kvm_irq_routing, kvm_irq_routing_entry, kvm_mp_state, kvm_userspace_memory_region,
|
||||
@@ -86,6 +84,8 @@ use kvm_bindings::{
|
||||
KVM_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK,
|
||||
KVM_REG_ARM_CORE, KVM_REG_SIZE_U128, KVM_REG_SIZE_U32, KVM_REG_SIZE_U64,
|
||||
};
|
||||
#[cfg(feature = "tdx")]
|
||||
use kvm_bindings::{kvm_run__bindgen_ty_1, KVMIO};
|
||||
pub use kvm_ioctls;
|
||||
pub use kvm_ioctls::{Cap, Kvm};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -169,6 +169,52 @@ pub struct TdxCapabilities {
|
||||
pub cpuid_configs: [TdxCpuidConfig; TDX_MAX_NR_CPUID_CONFIGS],
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct KvmTdxExit {
|
||||
pub type_: u32,
|
||||
pub pad: u32,
|
||||
pub u: KvmTdxExitU,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union KvmTdxExitU {
|
||||
pub vmcall: KvmTdxExitVmcall,
|
||||
}
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
||||
pub struct KvmTdxExitVmcall {
|
||||
pub type_: u64,
|
||||
pub subfunction: u64,
|
||||
pub reg_mask: u64,
|
||||
pub in_r12: u64,
|
||||
pub in_r13: u64,
|
||||
pub in_r14: u64,
|
||||
pub in_r15: u64,
|
||||
pub in_rbx: u64,
|
||||
pub in_rdi: u64,
|
||||
pub in_rsi: u64,
|
||||
pub in_r8: u64,
|
||||
pub in_r9: u64,
|
||||
pub in_rdx: u64,
|
||||
pub status_code: u64,
|
||||
pub out_r11: u64,
|
||||
pub out_r12: u64,
|
||||
pub out_r13: u64,
|
||||
pub out_r14: u64,
|
||||
pub out_r15: u64,
|
||||
pub out_rbx: u64,
|
||||
pub out_rdi: u64,
|
||||
pub out_rsi: u64,
|
||||
pub out_r8: u64,
|
||||
pub out_r9: u64,
|
||||
pub out_rdx: u64,
|
||||
}
|
||||
|
||||
impl From<kvm_userspace_memory_region> for UserMemoryRegion {
|
||||
fn from(region: kvm_userspace_memory_region) -> Self {
|
||||
let mut flags = USER_MEMORY_REGION_READ;
|
||||
@@ -356,6 +402,7 @@ impl vm::Vm for KvmVm {
|
||||
.set_identity_map_address(address)
|
||||
.map_err(|e| vm::HypervisorVmError::SetIdentityMapAddress(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the three-page region in the VM's address space.
|
||||
@@ -365,6 +412,7 @@ impl vm::Vm for KvmVm {
|
||||
.set_tss_address(offset)
|
||||
.map_err(|e| vm::HypervisorVmError::SetTssAddress(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates an in-kernel interrupt controller.
|
||||
///
|
||||
@@ -373,6 +421,7 @@ impl vm::Vm for KvmVm {
|
||||
.create_irq_chip()
|
||||
.map_err(|e| vm::HypervisorVmError::CreateIrq(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Registers an event that will, when signaled, trigger the `gsi` IRQ.
|
||||
///
|
||||
@@ -381,6 +430,7 @@ impl vm::Vm for KvmVm {
|
||||
.register_irqfd(fd, gsi)
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
|
||||
///
|
||||
@@ -389,6 +439,7 @@ impl vm::Vm for KvmVm {
|
||||
.unregister_irqfd(fd, gsi)
|
||||
.map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a VcpuFd object from a vcpu RawFd.
|
||||
///
|
||||
@@ -411,6 +462,7 @@ impl vm::Vm for KvmVm {
|
||||
};
|
||||
Ok(Arc::new(vcpu))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
///
|
||||
/// Creates a virtual GIC device.
|
||||
@@ -420,6 +472,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::CreateVgic(anyhow!("Vgic error {:?}", e)))?;
|
||||
Ok(Arc::new(Mutex::new(gic_device)))
|
||||
}
|
||||
|
||||
///
|
||||
/// Registers an event to be signaled whenever a certain address is written to.
|
||||
///
|
||||
@@ -447,6 +500,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Unregisters an event from a certain address it has been previously registered to.
|
||||
///
|
||||
@@ -541,6 +595,7 @@ impl vm::Vm for KvmVm {
|
||||
.set_gsi_routing(&irq_routing[0])
|
||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a memory region structure that can be used with {create/remove}_user_memory_region
|
||||
///
|
||||
@@ -567,6 +622,7 @@ impl vm::Vm for KvmVm {
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a guest physical memory region.
|
||||
///
|
||||
@@ -603,6 +659,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Removes a guest physical memory region.
|
||||
///
|
||||
@@ -621,6 +678,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
|
||||
///
|
||||
@@ -630,6 +688,7 @@ impl vm::Vm for KvmVm {
|
||||
.get_preferred_target(kvi)
|
||||
.map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||
// Create split irqchip
|
||||
@@ -645,6 +704,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_sgx_attribute(&self, file: File) -> vm::Result<()> {
|
||||
let mut cap = kvm_enable_cap {
|
||||
@@ -657,6 +717,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::EnableSgxAttribute(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Retrieve guest clock.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn get_clock(&self) -> vm::Result<ClockData> {
|
||||
@@ -666,6 +727,7 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::GetClock(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
/// Set guest clock.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn set_clock(&self, data: &ClockData) -> vm::Result<()> {
|
||||
@@ -674,6 +736,7 @@ impl vm::Vm for KvmVm {
|
||||
.set_clock(&data)
|
||||
.map_err(|e| vm::HypervisorVmError::SetClock(e.into()))
|
||||
}
|
||||
|
||||
/// Create a device that is used for passthrough
|
||||
fn create_passthrough_device(&self) -> vm::Result<VfioDeviceFd> {
|
||||
let mut vfio_dev = kvm_create_device {
|
||||
@@ -685,6 +748,7 @@ impl vm::Vm for KvmVm {
|
||||
self.create_device(&mut vfio_dev)
|
||||
.map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Start logging dirty pages
|
||||
///
|
||||
@@ -826,6 +890,7 @@ impl vm::Vm for KvmVm {
|
||||
)
|
||||
.map_err(vm::HypervisorVmError::InitMemRegionTdx)
|
||||
}
|
||||
|
||||
/// Downcast to the underlying KvmVm type
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
@@ -892,7 +957,9 @@ pub enum KvmError {
|
||||
#[error("Capability missing: {0:?}")]
|
||||
CapabilityMissing(Cap),
|
||||
}
|
||||
|
||||
pub type KvmResult<T> = result::Result<T, KvmError>;
|
||||
|
||||
impl KvmHypervisor {
|
||||
/// Create a hypervisor based on Kvm
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
@@ -906,6 +973,7 @@ impl KvmHypervisor {
|
||||
|
||||
Ok(Arc::new(KvmHypervisor { kvm: kvm_obj }))
|
||||
}
|
||||
|
||||
/// Check if the hypervisor is available
|
||||
pub fn is_available() -> hypervisor::Result<bool> {
|
||||
match std::fs::metadata("/dev/kvm") {
|
||||
@@ -917,6 +985,7 @@ impl KvmHypervisor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of Hypervisor trait for KVM
|
||||
///
|
||||
/// # Examples
|
||||
@@ -935,6 +1004,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
fn hypervisor_type(&self) -> HypervisorType {
|
||||
HypervisorType::Kvm
|
||||
}
|
||||
|
||||
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object
|
||||
///
|
||||
/// # Examples
|
||||
@@ -1090,6 +1160,7 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// Vcpu struct for KVM
|
||||
pub struct KvmVcpu {
|
||||
fd: VcpuFd,
|
||||
@@ -1099,6 +1170,7 @@ pub struct KvmVcpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
hyperv_synic: AtomicBool,
|
||||
}
|
||||
|
||||
/// Implementation of Vcpu trait for KVM
|
||||
///
|
||||
/// # Examples
|
||||
@@ -1123,6 +1195,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the vCPU general purpose registers.
|
||||
/// The `KVM_GET_REGS` ioctl is not available on AArch64, `KVM_GET_ONE_REG`
|
||||
@@ -1137,71 +1210,64 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// These actually are the general-purpose registers of the Armv8-a
|
||||
// architecture (i.e x0-x30 if used as a 64bit register or w0-30 when used as a 32bit register).
|
||||
for i in 0..31 {
|
||||
state.regs.regs[i] = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.regs.regs[i] = u64::from_le_bytes(bytes);
|
||||
off += std::mem::size_of::<u64>();
|
||||
}
|
||||
|
||||
// We are now entering the "Other register" section of the ARMv8-a architecture.
|
||||
// First one, stack pointer.
|
||||
let off = offset_of!(user_pt_regs, sp);
|
||||
state.regs.sp = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.regs.sp = u64::from_le_bytes(bytes);
|
||||
|
||||
// Second one, the program counter.
|
||||
let off = offset_of!(user_pt_regs, pc);
|
||||
state.regs.pc = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.regs.pc = u64::from_le_bytes(bytes);
|
||||
|
||||
// Next is the processor state.
|
||||
let off = offset_of!(user_pt_regs, pstate);
|
||||
state.regs.pstate = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.regs.pstate = u64::from_le_bytes(bytes);
|
||||
|
||||
// The stack pointer associated with EL1
|
||||
let off = offset_of!(kvm_regs, sp_el1);
|
||||
state.sp_el1 = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.sp_el1 = u64::from_le_bytes(bytes);
|
||||
|
||||
// Exception Link Register for EL1, when taking an exception to EL1, this register
|
||||
// holds the address to which to return afterwards.
|
||||
let off = offset_of!(kvm_regs, elr_el1);
|
||||
state.elr_el1 = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.elr_el1 = u64::from_le_bytes(bytes);
|
||||
|
||||
// Saved Program Status Registers, there are 5 of them used in the kernel.
|
||||
let mut off = offset_of!(kvm_regs, spsr);
|
||||
for i in 0..KVM_NR_SPSR as usize {
|
||||
state.spsr[i] = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.spsr[i] = u64::from_le_bytes(bytes);
|
||||
off += std::mem::size_of::<u64>();
|
||||
}
|
||||
|
||||
@@ -1209,32 +1275,32 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// https://elixir.free-electrons.com/linux/v4.9.62/source/arch/arm64/include/uapi/asm/kvm.h#L53
|
||||
let mut off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, vregs);
|
||||
for i in 0..32 {
|
||||
state.fp_regs.vregs[i] = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off))
|
||||
let mut bytes = [0_u8; 16];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U128, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.fp_regs.vregs[i] = u128::from_le_bytes(bytes);
|
||||
off += mem::size_of::<u128>();
|
||||
}
|
||||
|
||||
// Floating-point Status Register
|
||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpsr);
|
||||
state.fp_regs.fpsr = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 4];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.fp_regs.fpsr = u32::from_le_bytes(bytes);
|
||||
|
||||
// Floating-point Control Register
|
||||
let off = offset_of!(kvm_regs, fp_regs) + offset_of!(user_fpsimd_state, fpcr);
|
||||
state.fp_regs.fpcr = self
|
||||
.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let mut bytes = [0_u8; 4];
|
||||
self.fd
|
||||
.get_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U32, off), &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCoreRegister(e.into()))?;
|
||||
state.fp_regs.fpcr = u32::from_le_bytes(bytes);
|
||||
Ok(state)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl.
|
||||
@@ -1260,7 +1326,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.regs.regs[i].into(),
|
||||
&state.regs.regs[i].to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
off += std::mem::size_of::<u64>();
|
||||
@@ -1270,7 +1336,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.regs.sp.into(),
|
||||
&state.regs.sp.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1278,7 +1344,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.regs.pc.into(),
|
||||
&state.regs.pc.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1286,7 +1352,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.regs.pstate.into(),
|
||||
&state.regs.pstate.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1294,7 +1360,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.sp_el1.into(),
|
||||
&state.sp_el1.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1302,7 +1368,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.elr_el1.into(),
|
||||
&state.elr_el1.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1311,7 +1377,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, off),
|
||||
state.spsr[i].into(),
|
||||
&state.spsr[i].to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
off += std::mem::size_of::<u64>();
|
||||
@@ -1322,7 +1388,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U128, off),
|
||||
state.fp_regs.vregs[i],
|
||||
&state.fp_regs.vregs[i].to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
off += mem::size_of::<u128>();
|
||||
@@ -1332,7 +1398,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
||||
state.fp_regs.fpsr.into(),
|
||||
&state.fp_regs.fpsr.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1340,7 +1406,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U32, off),
|
||||
state.fp_regs.fpcr.into(),
|
||||
&state.fp_regs.fpcr.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
Ok(())
|
||||
@@ -1357,6 +1423,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl.
|
||||
@@ -1367,6 +1434,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_sregs(&sregs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the floating point state (FPU) from the vCPU.
|
||||
@@ -1378,6 +1446,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct.
|
||||
@@ -1388,6 +1457,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_fpu(&fpu)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to setup the CPUID registers.
|
||||
@@ -1402,6 +1472,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_cpuid2(&kvm_cpuid)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to enable HyperV SynIC
|
||||
@@ -1419,6 +1490,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.enable_cap(&cap)
|
||||
.map_err(|e| cpu::HypervisorCpuError::EnableHyperVSyncIc(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// X86 specific call to retrieve the CPUID registers.
|
||||
///
|
||||
@@ -1433,6 +1505,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
@@ -1444,6 +1517,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
@@ -1454,6 +1528,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_lapic(&klapic)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the model-specific registers (MSR) for this vCPU.
|
||||
@@ -1475,6 +1550,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
|
||||
Ok(succ)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Setup the model-specific registers (MSR) for this vCPU.
|
||||
@@ -1487,6 +1563,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_msrs(&kvm_msrs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the vcpu's current "multiprocessing state".
|
||||
///
|
||||
@@ -1497,6 +1574,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets the vcpu's current "multiprocessing state".
|
||||
///
|
||||
@@ -1505,6 +1583,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_mp_state(mp_state.into())
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Translates guest virtual address to guest physical address using the `KVM_TRANSLATE` ioctl.
|
||||
@@ -1523,6 +1602,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
_ => Ok((tr.physical_address, 0)),
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Triggers the running of the current virtual CPU returning an exit reason.
|
||||
///
|
||||
@@ -1567,7 +1647,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
Ok(cpu::VmExit::Shutdown)
|
||||
} else {
|
||||
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||
"Unexpected system event with type 0x{:x}, flags 0x{:x}",
|
||||
"Unexpected system event with type 0x{:x}, flags 0x{:x?}",
|
||||
event_type,
|
||||
flags
|
||||
)))
|
||||
@@ -1614,6 +1694,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Let the guest know that it has been paused, which prevents from
|
||||
@@ -1631,6 +1712,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets debug registers to set hardware breakpoints and/or enable single step.
|
||||
///
|
||||
@@ -1684,12 +1766,14 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.set_guest_debug(&dbg)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
||||
self.fd
|
||||
.vcpu_init(kvi)
|
||||
.map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Gets a list of the guest registers that are supported for the
|
||||
/// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls.
|
||||
@@ -1700,6 +1784,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
.get_reg_list(reg_list)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetRegList(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Gets the value of a system register
|
||||
///
|
||||
@@ -1726,13 +1811,13 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
| KVM_REG_ARM64_SYSREG_CRN_MASK
|
||||
| KVM_REG_ARM64_SYSREG_CRM_MASK
|
||||
| KVM_REG_ARM64_SYSREG_OP2_MASK)) as u64);
|
||||
Ok(self
|
||||
.fd
|
||||
.get_one_reg(id)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap())
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(id, &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
|
||||
Ok(u64::from_le_bytes(bytes))
|
||||
}
|
||||
|
||||
///
|
||||
/// Configure core registers for a given CPU.
|
||||
///
|
||||
@@ -1757,7 +1842,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, pstate),
|
||||
PSTATE_FAULT_BITS_64.into(),
|
||||
&PSTATE_FAULT_BITS_64.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
@@ -1766,7 +1851,10 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// Setting the PC (Processor Counter) to the current program address (kernel address).
|
||||
let pc = offset_of!(user_pt_regs, pc) + kreg_off;
|
||||
self.fd
|
||||
.set_one_reg(arm64_core_reg_id!(KVM_REG_SIZE_U64, pc), boot_ip.into())
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, pc),
|
||||
&boot_ip.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
|
||||
// Last mandatory thing to set -> the address pointing to the FDT (also called DTB).
|
||||
@@ -1777,7 +1865,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
self.fd
|
||||
.set_one_reg(
|
||||
arm64_core_reg_id!(KVM_REG_SIZE_U64, regs0),
|
||||
fdt_start.into(),
|
||||
&fdt_start.to_le_bytes(),
|
||||
)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCoreRegister(e.into()))?;
|
||||
}
|
||||
@@ -1907,6 +1995,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
///
|
||||
/// Get the current AArch64 CPU state
|
||||
///
|
||||
@@ -1941,14 +2030,13 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// register list, we are simply calling KVM_GET_ONE_REG.
|
||||
let indices = reg_list.as_slice();
|
||||
for index in indices.iter() {
|
||||
let mut bytes = [0_u8; 8];
|
||||
self.fd
|
||||
.get_one_reg(*index, &mut bytes)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?;
|
||||
sys_regs.push(kvm_bindings::kvm_one_reg {
|
||||
id: *index,
|
||||
addr: self
|
||||
.fd
|
||||
.get_one_reg(*index)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSysRegister(e.into()))?
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
addr: u64::from_le_bytes(bytes),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1956,6 +2044,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
|
||||
Ok(state.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Restore the previously saved CPU state
|
||||
@@ -2045,6 +2134,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Restore the previously saved AArch64 CPU state
|
||||
///
|
||||
@@ -2056,7 +2146,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
// Set system registers
|
||||
for reg in &state.sys_regs {
|
||||
self.fd
|
||||
.set_one_reg(reg.id, reg.addr.into())
|
||||
.set_one_reg(reg.id, ®.addr.to_le_bytes())
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetSysRegister(e.into()))?;
|
||||
}
|
||||
|
||||
@@ -2088,7 +2178,12 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
|
||||
let kvm_run = self.fd.get_kvm_run();
|
||||
// SAFETY: accessing a union field in a valid structure
|
||||
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
||||
let tdx_vmcall = unsafe {
|
||||
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
|
||||
as *mut KvmTdxExit))
|
||||
.u
|
||||
.vmcall
|
||||
};
|
||||
|
||||
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
|
||||
|
||||
@@ -2112,13 +2207,19 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
fn set_tdx_status(&mut self, status: TdxExitStatus) {
|
||||
let kvm_run = self.fd.get_kvm_run();
|
||||
// SAFETY: accessing a union field in a valid structure
|
||||
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
||||
let tdx_vmcall = unsafe {
|
||||
&mut (*((&mut kvm_run.__bindgen_anon_1) as *mut kvm_run__bindgen_ty_1
|
||||
as *mut KvmTdxExit))
|
||||
.u
|
||||
.vmcall
|
||||
};
|
||||
|
||||
tdx_vmcall.status_code = match status {
|
||||
TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS,
|
||||
TdxExitStatus::InvalidOperand => TDG_VP_VMCALL_INVALID_OPERAND,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Return the list of initial MSR entries for a VCPU
|
||||
@@ -2144,6 +2245,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
]
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn has_pmu_support(&self) -> bool {
|
||||
let cpu_attr = kvm_bindings::kvm_device_attr {
|
||||
@@ -2154,6 +2256,7 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
};
|
||||
self.fd.has_device_attr(&cpu_attr).is_ok()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn init_pmu(&self, irq: u32) -> cpu::Result<()> {
|
||||
let cpu_attr = kvm_bindings::kvm_device_attr {
|
||||
@@ -2216,20 +2319,25 @@ impl KvmVcpu {
|
||||
///
|
||||
/// X86 specific call that returns the vcpu's current "xsave struct".
|
||||
///
|
||||
fn get_xsave(&self) -> cpu::Result<Xsave> {
|
||||
self.fd
|
||||
fn get_xsave(&self) -> cpu::Result<XsaveState> {
|
||||
Ok(self
|
||||
.fd
|
||||
.get_xsave()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that sets the vcpu's current "xsave struct".
|
||||
///
|
||||
fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
|
||||
fn set_xsave(&self, xsave: &XsaveState) -> cpu::Result<()> {
|
||||
let xsave: kvm_bindings::kvm_xsave = (*xsave).clone().into();
|
||||
self.fd
|
||||
.set_xsave(xsave)
|
||||
.set_xsave(&xsave)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that returns the vcpu's current "xcrs".
|
||||
@@ -2239,6 +2347,7 @@ impl KvmVcpu {
|
||||
.get_xcrs()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that sets the vcpu's current "xcrs".
|
||||
@@ -2248,6 +2357,7 @@ impl KvmVcpu {
|
||||
.set_xcrs(xcrs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns currently pending exceptions, interrupts, and NMIs as well as related
|
||||
@@ -2258,6 +2368,7 @@ impl KvmVcpu {
|
||||
.get_vcpu_events()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets pending exceptions, interrupts, and NMIs as well as related states
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
use crate::arch::x86::{
|
||||
CpuIdEntry, DescriptorTable, FpuState, LapicState, MsrEntry, SegmentRegister, SpecialRegisters,
|
||||
StandardRegisters, CPUID_FLAG_VALID_INDEX,
|
||||
StandardRegisters, XsaveState, CPUID_FLAG_VALID_INDEX,
|
||||
};
|
||||
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -23,7 +23,7 @@ pub use {
|
||||
kvm_bindings::kvm_lapic_state, kvm_bindings::kvm_mp_state as MpState,
|
||||
kvm_bindings::kvm_msr_entry, kvm_bindings::kvm_regs, kvm_bindings::kvm_segment,
|
||||
kvm_bindings::kvm_sregs, kvm_bindings::kvm_vcpu_events as VcpuEvents,
|
||||
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave as Xsave,
|
||||
kvm_bindings::kvm_xcrs as ExtendedControlRegisters, kvm_bindings::kvm_xsave,
|
||||
kvm_bindings::CpuId, kvm_bindings::MsrList, kvm_bindings::Msrs as MsrEntries,
|
||||
kvm_bindings::KVM_CPUID_FLAG_SIGNIFCANT_INDEX,
|
||||
};
|
||||
@@ -64,7 +64,7 @@ pub struct VcpuKvmState {
|
||||
pub sregs: kvm_sregs,
|
||||
pub fpu: FpuState,
|
||||
pub lapic_state: LapicState,
|
||||
pub xsave: Xsave,
|
||||
pub xsave: XsaveState,
|
||||
pub xcrs: ExtendedControlRegisters,
|
||||
pub mp_state: MpState,
|
||||
pub tsc_khz: Option<u32>,
|
||||
@@ -330,3 +330,18 @@ impl From<MsrEntry> for kvm_msr_entry {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<kvm_xsave> for XsaveState {
|
||||
fn from(s: kvm_xsave) -> Self {
|
||||
Self { region: s.region }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<XsaveState> for kvm_xsave {
|
||||
fn from(s: XsaveState) -> Self {
|
||||
Self {
|
||||
region: s.region,
|
||||
extra: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,7 @@ pub const USER_MEMORY_REGION_READ: u32 = 1;
|
||||
pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
|
||||
pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
|
||||
pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
|
||||
pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MpState {
|
||||
|
||||
@@ -31,7 +31,8 @@ use snp_constants::*;
|
||||
|
||||
use crate::{
|
||||
ClockData, CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
|
||||
USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ, USER_MEMORY_REGION_WRITE,
|
||||
USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ,
|
||||
USER_MEMORY_REGION_WRITE,
|
||||
};
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
|
||||
@@ -73,6 +74,9 @@ impl From<mshv_user_mem_region> for UserMemoryRegion {
|
||||
if region.flags & HV_MAP_GPA_EXECUTABLE != 0 {
|
||||
flags |= USER_MEMORY_REGION_EXECUTE;
|
||||
}
|
||||
if region.flags & HV_MAP_GPA_ADJUSTABLE != 0 {
|
||||
flags |= USER_MEMORY_REGION_ADJUSTABLE;
|
||||
}
|
||||
|
||||
UserMemoryRegion {
|
||||
guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64)
|
||||
@@ -97,6 +101,9 @@ impl From<UserMemoryRegion> for mshv_user_mem_region {
|
||||
if region.flags & USER_MEMORY_REGION_EXECUTE != 0 {
|
||||
flags |= HV_MAP_GPA_EXECUTABLE;
|
||||
}
|
||||
if region.flags & USER_MEMORY_REGION_ADJUSTABLE != 0 {
|
||||
flags |= HV_MAP_GPA_ADJUSTABLE;
|
||||
}
|
||||
|
||||
mshv_user_mem_region {
|
||||
guest_pfn: region.guest_phys_addr >> PAGE_SHIFT,
|
||||
@@ -200,6 +207,7 @@ impl MshvHypervisor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of Hypervisor trait for Mshv
|
||||
///
|
||||
/// # Examples
|
||||
@@ -298,6 +306,8 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
fd: vm_fd,
|
||||
msrs,
|
||||
dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
|
||||
#[cfg(feature = "sev_snp")]
|
||||
sev_snp_enabled: mshv_vm_type == VmType::Snp,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -338,6 +348,8 @@ pub struct MshvVcpu {
|
||||
cpuid: Vec<CpuIdEntry>,
|
||||
msrs: Vec<MsrEntry>,
|
||||
vm_ops: Option<Arc<dyn vm::VmOps>>,
|
||||
#[cfg(feature = "sev_snp")]
|
||||
vm_fd: Arc<VmFd>,
|
||||
}
|
||||
|
||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||
@@ -364,6 +376,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the vCPU general purpose registers.
|
||||
@@ -374,6 +387,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.set_regs(®s)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the vCPU special registers.
|
||||
@@ -385,6 +399,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the vCPU special registers.
|
||||
@@ -395,6 +410,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.set_sregs(&sregs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the floating point state (FPU) from the vCPU.
|
||||
@@ -406,6 +422,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Set the floating point state (FPU) of a vCPU.
|
||||
@@ -438,6 +455,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
|
||||
Ok(succ)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Setup the model-specific registers (MSR) for this vCPU.
|
||||
@@ -459,6 +477,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* We always have SynIC enabled on MSHV */
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
|
||||
let hv_message: hv_message = hv_message::default();
|
||||
@@ -587,6 +606,17 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
|
||||
Ok(cpu::VmExit::Ignore)
|
||||
}
|
||||
hv_message_type_HVMSG_UNACCEPTED_GPA => {
|
||||
let info = x.to_memory_info().unwrap();
|
||||
let gva = info.guest_virtual_address;
|
||||
let gpa = info.guest_physical_address;
|
||||
|
||||
Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||
"Unhandled VCPU exit: Unaccepted GPA({:x}) found at GVA({:x})",
|
||||
gpa,
|
||||
gva,
|
||||
)))
|
||||
}
|
||||
hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
|
||||
let info = x.to_cpuid_info().unwrap();
|
||||
debug!("cpuid eax: {:x}", { info.rax });
|
||||
@@ -976,6 +1006,59 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
})?;
|
||||
}
|
||||
}
|
||||
SVM_EXITCODE_SNP_GUEST_REQUEST => {
|
||||
let req_gpa =
|
||||
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
|
||||
let rsp_gpa =
|
||||
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
|
||||
|
||||
let mshv_psp_req =
|
||||
mshv_issue_psp_guest_request { req_gpa, rsp_gpa };
|
||||
self.vm_fd
|
||||
.psp_issue_guest_request(&mshv_psp_req)
|
||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
||||
|
||||
debug!(
|
||||
"SNP guest request: req_gpa {:0x} rsp_gpa {:0x}",
|
||||
req_gpa, rsp_gpa
|
||||
);
|
||||
|
||||
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
|
||||
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
|
||||
byte_count: std::mem::size_of::<u64>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
self.fd
|
||||
.gpa_write(&mut swei2_rw_gpa_arg)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
|
||||
}
|
||||
SVM_EXITCODE_SNP_AP_CREATION => {
|
||||
let vmsa_gpa =
|
||||
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
|
||||
let apic_id =
|
||||
info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 >> 32;
|
||||
debug!(
|
||||
"SNP AP CREATE REQUEST with VMSA GPA {:0x}, and APIC ID {:?}",
|
||||
vmsa_gpa, apic_id
|
||||
);
|
||||
|
||||
let mshv_ap_create_req = mshv_sev_snp_ap_create {
|
||||
vp_id: apic_id,
|
||||
vmsa_gpa,
|
||||
};
|
||||
self.vm_fd
|
||||
.sev_snp_ap_create(&mshv_ap_create_req)
|
||||
.map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
|
||||
|
||||
let mut swei2_rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
|
||||
base_gpa: ghcb_gpa + GHCB_SW_EXITINFO2_OFFSET,
|
||||
byte_count: std::mem::size_of::<u64>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
self.fd
|
||||
.gpa_write(&mut swei2_rw_gpa_arg)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
|
||||
}
|
||||
_ => panic!(
|
||||
"GHCB_INFO_NORMAL: Unhandled exit code: {:0x}",
|
||||
exit_code
|
||||
@@ -1002,6 +1085,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to setup the CPUID registers.
|
||||
@@ -1015,6 +1099,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.register_intercept_result_cpuid(&mshv_cpuid)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to retrieve the CPUID registers.
|
||||
@@ -1022,6 +1107,23 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
|
||||
Ok(self.cpuid.clone())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call to retrieve cpuid leaf
|
||||
///
|
||||
fn get_cpuid_values(
|
||||
&self,
|
||||
function: u32,
|
||||
index: u32,
|
||||
xfem: u64,
|
||||
xss: u64,
|
||||
) -> cpu::Result<[u32; 4]> {
|
||||
self.fd
|
||||
.get_cpuid_values(function, index, xfem, xss)
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetCpuidVales(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
@@ -1033,6 +1135,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
|
||||
@@ -1043,18 +1146,21 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.set_lapic(&lapic)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Returns the vcpu's current "multiprocessing state".
|
||||
///
|
||||
fn get_mp_state(&self) -> cpu::Result<MpState> {
|
||||
Ok(MpState::Mshv)
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets the vcpu's current "multiprocessing state".
|
||||
///
|
||||
fn set_mp_state(&self, _mp_state: MpState) -> cpu::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Set CPU state
|
||||
///
|
||||
@@ -1080,6 +1186,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Get CPU State
|
||||
///
|
||||
@@ -1116,6 +1223,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
}
|
||||
.into())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Translate guest virtual address to guest physical address
|
||||
@@ -1132,6 +1240,7 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
|
||||
Ok((gpa, result_code))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Return the list of initial MSR entries for a VCPU
|
||||
@@ -1152,6 +1261,18 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
]
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
///
|
||||
/// Sets the AMD specific vcpu's sev control register.
|
||||
///
|
||||
#[cfg(feature = "sev_snp")]
|
||||
fn set_sev_control_register(&self, vmsa_pfn: u64) -> cpu::Result<()> {
|
||||
let sev_control_reg = snp::get_sev_control_register(vmsa_pfn);
|
||||
|
||||
self.fd
|
||||
.set_sev_control_register(sev_control_reg)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetSevControlRegister(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
impl MshvVcpu {
|
||||
@@ -1164,6 +1285,7 @@ impl MshvVcpu {
|
||||
.get_xsave()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that sets the vcpu's current "xsave struct".
|
||||
@@ -1173,6 +1295,7 @@ impl MshvVcpu {
|
||||
.set_xsave(xsave)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that returns the vcpu's current "xcrs".
|
||||
@@ -1182,6 +1305,7 @@ impl MshvVcpu {
|
||||
.get_xcrs()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// X86 specific call that sets the vcpu's current "xcrs".
|
||||
@@ -1191,6 +1315,7 @@ impl MshvVcpu {
|
||||
.set_xcrs(xcrs)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Returns currently pending exceptions, interrupts, and NMIs as well as related
|
||||
@@ -1201,6 +1326,7 @@ impl MshvVcpu {
|
||||
.get_vcpu_events()
|
||||
.map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets pending exceptions, interrupts, and NMIs as well as related states
|
||||
@@ -1343,6 +1469,8 @@ pub struct MshvVm {
|
||||
fd: Arc<VmFd>,
|
||||
msrs: Vec<MsrEntry>,
|
||||
dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
|
||||
#[cfg(feature = "sev_snp")]
|
||||
sev_snp_enabled: bool,
|
||||
}
|
||||
|
||||
impl MshvVm {
|
||||
@@ -1380,6 +1508,7 @@ impl vm::Vm for MshvVm {
|
||||
fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the three-page region in the VM's address space.
|
||||
@@ -1387,12 +1516,14 @@ impl vm::Vm for MshvVm {
|
||||
fn set_tss_address(&self, _offset: usize) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates an in-kernel interrupt controller.
|
||||
///
|
||||
fn create_irq_chip(&self) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Registers an event that will, when signaled, trigger the `gsi` IRQ.
|
||||
///
|
||||
@@ -1405,6 +1536,7 @@ impl vm::Vm for MshvVm {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
|
||||
///
|
||||
@@ -1417,6 +1549,7 @@ impl vm::Vm for MshvVm {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Creates a VcpuFd object from a vcpu RawFd.
|
||||
///
|
||||
@@ -1435,23 +1568,33 @@ impl vm::Vm for MshvVm {
|
||||
cpuid: Vec::new(),
|
||||
msrs: self.msrs.clone(),
|
||||
vm_ops,
|
||||
#[cfg(feature = "sev_snp")]
|
||||
vm_fd: self.fd.clone(),
|
||||
};
|
||||
Ok(Arc::new(vcpu))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn register_ioevent(
|
||||
&self,
|
||||
fd: &EventFd,
|
||||
addr: &IoEventAddress,
|
||||
datamatch: Option<DataMatch>,
|
||||
) -> vm::Result<()> {
|
||||
#[cfg(feature = "sev_snp")]
|
||||
if self.sev_snp_enabled {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
||||
debug!(
|
||||
"register_ioevent fd {} addr {:x?} datamatch {:?}",
|
||||
@@ -1476,6 +1619,7 @@ impl vm::Vm for MshvVm {
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Unregister an event from a certain address it has been previously registered to.
|
||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
|
||||
let addr = &mshv_ioctls::IoEventAddress::from(*addr);
|
||||
@@ -1530,7 +1674,7 @@ impl vm::Vm for MshvVm {
|
||||
readonly: bool,
|
||||
_log_dirty_pages: bool,
|
||||
) -> UserMemoryRegion {
|
||||
let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE;
|
||||
let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE | HV_MAP_GPA_ADJUSTABLE;
|
||||
if !readonly {
|
||||
flags |= HV_MAP_GPA_WRITABLE;
|
||||
}
|
||||
@@ -1600,6 +1744,7 @@ impl vm::Vm for MshvVm {
|
||||
.set_msi_routing(&msi_routing[0])
|
||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Start logging dirty pages
|
||||
///
|
||||
@@ -1608,6 +1753,7 @@ impl vm::Vm for MshvVm {
|
||||
.enable_dirty_page_tracking()
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Stop logging dirty pages
|
||||
///
|
||||
@@ -1626,6 +1772,7 @@ impl vm::Vm for MshvVm {
|
||||
.map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
/// Get dirty pages bitmap (one bit per page)
|
||||
///
|
||||
@@ -1638,20 +1785,24 @@ impl vm::Vm for MshvVm {
|
||||
)
|
||||
.map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
|
||||
}
|
||||
|
||||
/// Retrieve guest clock.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn get_clock(&self) -> vm::Result<ClockData> {
|
||||
Ok(ClockData::Mshv)
|
||||
}
|
||||
|
||||
/// Set guest clock.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn set_clock(&self, _data: &ClockData) -> vm::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Downcast to the underlying MshvVm type
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
/// Initialize the SEV-SNP VM
|
||||
#[cfg(feature = "sev_snp")]
|
||||
fn sev_snp_init(&self) -> vm::Result<()> {
|
||||
@@ -1663,6 +1814,9 @@ impl vm::Vm for MshvVm {
|
||||
.map_err(|e| vm::HypervisorVmError::InitializeSevSnp(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Importing isolated pages, these pages will be used
|
||||
/// for the PSP(Platform Security Processor) measurement.
|
||||
#[cfg(feature = "sev_snp")]
|
||||
fn import_isolated_pages(
|
||||
&self,
|
||||
@@ -1690,11 +1844,16 @@ impl vm::Vm for MshvVm {
|
||||
.import_isolated_pages(&isolated_pages[0])
|
||||
.map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into()))
|
||||
}
|
||||
|
||||
///
|
||||
/// Complete isolated import, telling the hypervisor that
|
||||
/// importing the pages to guest memory is complete.
|
||||
///
|
||||
#[cfg(feature = "sev_snp")]
|
||||
fn complete_isolated_import(
|
||||
&self,
|
||||
snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
||||
host_data: &[u8],
|
||||
host_data: [u8; 32],
|
||||
id_block_enabled: u8,
|
||||
) -> vm::Result<()> {
|
||||
let mut auth_info = hv_snp_id_auth_info {
|
||||
@@ -1727,7 +1886,7 @@ impl vm::Vm for MshvVm {
|
||||
policy: get_default_snp_guest_policy(),
|
||||
},
|
||||
id_auth_info: auth_info,
|
||||
host_data: host_data[0..32].try_into().unwrap(),
|
||||
host_data,
|
||||
id_block_enabled,
|
||||
author_key_enabled: 0,
|
||||
},
|
||||
|
||||
@@ -385,7 +385,7 @@ pub trait Vm: Send + Sync + Any {
|
||||
fn complete_isolated_import(
|
||||
&self,
|
||||
_snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
|
||||
_host_data: &[u8],
|
||||
_host_data: [u8; 32],
|
||||
_id_block_enabled: u8,
|
||||
) -> Result<()> {
|
||||
unimplemented!()
|
||||
|
||||
@@ -5,4 +5,4 @@ authors = ["The Chromium OS Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -6,23 +6,23 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
epoll = "4.3.3"
|
||||
getrandom = "0.2.10"
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
getrandom = "0.2.11"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.168"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
serde = "1.0.196"
|
||||
thiserror = "1.0.52"
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.9.0"
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.11.0"
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
[dev-dependencies]
|
||||
once_cell = "1.18.0"
|
||||
once_cell = "1.19.0"
|
||||
pnet = "0.34.0"
|
||||
pnet_datalink = "0.34.0"
|
||||
serde_json = "1.0.107"
|
||||
serde_json = "1.0.109"
|
||||
|
||||
@@ -72,6 +72,10 @@ pub fn open_tap(
|
||||
let mut taps: Vec<Tap> = Vec::new();
|
||||
let mut ifname: String = String::new();
|
||||
let vnet_hdr_size = vnet_hdr_len() as i32;
|
||||
// Check if the given interface exists before we create it.
|
||||
let tap_existed = if_name.map_or(false, |n| {
|
||||
Path::new(&format!("/sys/class/net/{n}")).exists()
|
||||
});
|
||||
|
||||
// In case the tap interface already exists, check if the number of
|
||||
// queues is appropriate. The tap might not support multiqueue while
|
||||
@@ -87,11 +91,19 @@ pub fn open_tap(
|
||||
Some(name) => Tap::open_named(name, num_rx_q, flags).map_err(Error::TapOpen)?,
|
||||
None => Tap::new(num_rx_q).map_err(Error::TapOpen)?,
|
||||
};
|
||||
if let Some(ip) = ip_addr {
|
||||
tap.set_ip_addr(ip).map_err(Error::TapSetIp)?;
|
||||
}
|
||||
if let Some(mask) = netmask {
|
||||
tap.set_netmask(mask).map_err(Error::TapSetNetmask)?;
|
||||
// Don't overwrite ip configuration of existing interfaces:
|
||||
if !tap_existed {
|
||||
if let Some(ip) = ip_addr {
|
||||
tap.set_ip_addr(ip).map_err(Error::TapSetIp)?;
|
||||
}
|
||||
if let Some(mask) = netmask {
|
||||
tap.set_netmask(mask).map_err(Error::TapSetNetmask)?;
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Tap {} already exists. IP configuration will not be overwritten.",
|
||||
if_name.unwrap_or_default()
|
||||
);
|
||||
}
|
||||
if let Some(mac) = host_mac {
|
||||
tap.set_mac_addr(*mac).map_err(Error::TapSetMac)?
|
||||
|
||||
@@ -290,6 +290,17 @@ impl TupleValue for Vec<u64> {
|
||||
}
|
||||
}
|
||||
|
||||
impl TupleValue for Vec<usize> {
|
||||
fn parse_value(input: &str) -> Result<Self, TupleError> {
|
||||
Ok(IntegerList::from_str(input)
|
||||
.map_err(TupleError::InvalidIntegerList)?
|
||||
.0
|
||||
.iter()
|
||||
.map(|v| *v as usize)
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Tuple<S, T>(pub Vec<(S, T)>);
|
||||
|
||||
pub enum TupleError {
|
||||
|
||||
@@ -10,21 +10,21 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||
|
||||
vmm-sys-util = "0.11.0"
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.168", features = ["derive"] }
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vmm-sys-util = "0.12.1"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
thiserror = "1.0.52"
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
@@ -58,7 +58,8 @@ pub trait PciDevice: BusDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
_allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
_mmio_allocator: &mut AddressAllocator,
|
||||
_mmio32_allocator: &mut AddressAllocator,
|
||||
_mmio64_allocator: &mut AddressAllocator,
|
||||
_resources: Option<Vec<Resource>>,
|
||||
) -> Result<Vec<PciBarConfiguration>> {
|
||||
Ok(Vec::new())
|
||||
@@ -68,7 +69,8 @@ pub trait PciDevice: BusDevice {
|
||||
fn free_bars(
|
||||
&mut self,
|
||||
_allocator: &mut SystemAllocator,
|
||||
_mmio_allocator: &mut AddressAllocator,
|
||||
_mmio32_allocator: &mut AddressAllocator,
|
||||
_mmio64_allocator: &mut AddressAllocator,
|
||||
) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -529,10 +529,13 @@ impl VfioCommon {
|
||||
}
|
||||
}
|
||||
|
||||
// The `allocator` argument is unused on `aarch64`
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
resources: Option<Vec<Resource>>,
|
||||
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||
let mut bars = Vec::new();
|
||||
@@ -681,26 +684,23 @@ impl VfioCommon {
|
||||
}
|
||||
PciBarRegionType::Memory32BitRegion => {
|
||||
// BAR allocation must be naturally aligned
|
||||
allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_mmio_hole_addresses(
|
||||
restored_bar_addr,
|
||||
region_size,
|
||||
Some(region_size),
|
||||
)
|
||||
mmio32_allocator
|
||||
.allocate(restored_bar_addr, region_size, Some(region_size))
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
PciBarRegionType::Memory64BitRegion => {
|
||||
// We need do some fixup to keep MMIO RW region and msix cap region page size
|
||||
// aligned.
|
||||
region_size = self.fixup_msix_region(bar_id, region_size);
|
||||
mmio_allocator
|
||||
mmio64_allocator
|
||||
.allocate(
|
||||
restored_bar_addr,
|
||||
region_size,
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
|
||||
Some(std::cmp::max(
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
unsafe { sysconf(_SC_PAGESIZE) as GuestUsize },
|
||||
region_size,
|
||||
)),
|
||||
)
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
@@ -742,10 +742,13 @@ impl VfioCommon {
|
||||
Ok(bars)
|
||||
}
|
||||
|
||||
// The `allocator` argument is unused on `aarch64`
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn free_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
) -> Result<(), PciDeviceError> {
|
||||
for region in self.mmio_regions.iter() {
|
||||
match region.type_ {
|
||||
@@ -756,10 +759,10 @@ impl VfioCommon {
|
||||
error!("I/O region is not supported");
|
||||
}
|
||||
PciBarRegionType::Memory32BitRegion => {
|
||||
allocator.free_mmio_hole_addresses(region.start, region.length);
|
||||
mmio32_allocator.free(region.start, region.length);
|
||||
}
|
||||
PciBarRegionType::Memory64BitRegion => {
|
||||
mmio_allocator.free(region.start, region.length);
|
||||
mmio64_allocator.free(region.start, region.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1568,6 +1571,16 @@ impl VfioPciDevice {
|
||||
self.vm
|
||||
.create_user_memory_region(mem_region)
|
||||
.map_err(VfioPciError::CreateUserMemoryRegion)?;
|
||||
|
||||
if !self.iommu_attached {
|
||||
self.container
|
||||
.vfio_dma_map(
|
||||
user_memory_region.start,
|
||||
user_memory_region.size,
|
||||
user_memory_region.host_addr,
|
||||
)
|
||||
.map_err(VfioPciError::DmaMap)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1578,6 +1591,16 @@ impl VfioPciDevice {
|
||||
pub fn unmap_mmio_regions(&mut self) {
|
||||
for region in self.common.mmio_regions.iter() {
|
||||
for user_memory_region in region.user_memory_regions.iter() {
|
||||
// Unmap from vfio container
|
||||
if !self.iommu_attached {
|
||||
if let Err(e) = self
|
||||
.container
|
||||
.vfio_dma_unmap(user_memory_region.start, user_memory_region.size)
|
||||
{
|
||||
error!("Could not unmap mmio region from vfio container: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove region
|
||||
let r = self.vm.make_user_memory_region(
|
||||
user_memory_region.slot,
|
||||
@@ -1694,19 +1717,22 @@ impl PciDevice for VfioPciDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
resources: Option<Vec<Resource>>,
|
||||
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||
self.common
|
||||
.allocate_bars(allocator, mmio_allocator, resources)
|
||||
.allocate_bars(allocator, mmio32_allocator, mmio64_allocator, resources)
|
||||
}
|
||||
|
||||
fn free_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
) -> Result<(), PciDeviceError> {
|
||||
self.common.free_bars(allocator, mmio_allocator)
|
||||
self.common
|
||||
.free_bars(allocator, mmio32_allocator, mmio64_allocator)
|
||||
}
|
||||
|
||||
fn write_config_register(
|
||||
|
||||
@@ -397,19 +397,22 @@ impl PciDevice for VfioUserPciDevice {
|
||||
fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
resources: Option<Vec<Resource>>,
|
||||
) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
|
||||
self.common
|
||||
.allocate_bars(allocator, mmio_allocator, resources)
|
||||
.allocate_bars(allocator, mmio32_allocator, mmio64_allocator, resources)
|
||||
}
|
||||
|
||||
fn free_bars(
|
||||
&mut self,
|
||||
allocator: &mut SystemAllocator,
|
||||
mmio_allocator: &mut AddressAllocator,
|
||||
mmio32_allocator: &mut AddressAllocator,
|
||||
mmio64_allocator: &mut AddressAllocator,
|
||||
) -> Result<(), PciDeviceError> {
|
||||
self.common.free_bars(allocator, mmio_allocator)
|
||||
self.common
|
||||
.free_bars(allocator, mmio32_allocator, mmio64_allocator)
|
||||
}
|
||||
|
||||
fn as_any(&mut self) -> &mut dyn Any {
|
||||
|
||||
@@ -6,10 +6,10 @@ edition = "2021"
|
||||
build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.0.32", features = ["wrap_help"] }
|
||||
clap = { version = "4.4.7", features = ["wrap_help"] }
|
||||
dirs = "5.0.0"
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.107"
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.109"
|
||||
test_infra = { path = "../test_infra" }
|
||||
thiserror = "1.0.40"
|
||||
thiserror = "1.0.52"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -19,6 +19,7 @@ pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-arm64-custom-20210929-0-update-tool.raw";
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
BootTimeParse,
|
||||
|
||||
@@ -4,6 +4,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
vmm-sys-util = "0.11.0"
|
||||
epoll = "4.3.3"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
thiserror = "1.0.40"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
526
rate_limiter/src/group.rs
Normal file
526
rate_limiter/src/group.rs
Normal file
@@ -0,0 +1,526 @@
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Copyright 2023 Crusoe Energy Systems LLC
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{RateLimiter, TokenType};
|
||||
use core::panic::AssertUnwindSafe;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
/// Errors associated with rate-limiter group.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Cannot create thread
|
||||
#[error("Error spawning rate-limiter thread {0}")]
|
||||
ThreadSpawn(#[source] io::Error),
|
||||
|
||||
/// Cannot create epoll context.
|
||||
#[error("Error creating epoll context: {0}")]
|
||||
Epoll(#[source] io::Error),
|
||||
|
||||
/// Cannot create EventFd.
|
||||
#[error("Error creating EventFd: {0}")]
|
||||
EventFd(#[source] io::Error),
|
||||
|
||||
/// Cannot create RateLimiter.
|
||||
#[error("Error creating RateLimiter: {0}")]
|
||||
RateLimiter(#[source] io::Error),
|
||||
|
||||
/// Cannot read from EventFd.
|
||||
#[error("Error reading from EventFd: {0}")]
|
||||
EventFdRead(#[source] io::Error),
|
||||
|
||||
/// Cannot write to EventFd.
|
||||
#[error("Error writing to EventFd: {0}")]
|
||||
EventFdWrite(#[source] io::Error),
|
||||
}
|
||||
|
||||
/// The RateLimiterGroupHandle is a handle to a RateLimiterGroup that may be
|
||||
/// used in exactly the same way as the RateLimiter type. When the RateLimiter
|
||||
/// within a RateLimiterGroup is unblocked, each RateLimiterGroupHandle will
|
||||
/// be notified.
|
||||
pub struct RateLimiterGroupHandle {
|
||||
eventfd: Arc<EventFd>,
|
||||
inner: Arc<RateLimiterGroupInner>,
|
||||
}
|
||||
|
||||
impl RateLimiterGroupHandle {
|
||||
fn new(inner: Arc<RateLimiterGroupInner>) -> result::Result<Self, Error> {
|
||||
let eventfd = Arc::new(EventFd::new(0).map_err(Error::EventFd)?);
|
||||
inner.handles.lock().unwrap().push(eventfd.clone());
|
||||
Ok(Self { eventfd, inner })
|
||||
}
|
||||
|
||||
/// Attempts to consume tokens and returns whether that is possible.
|
||||
///
|
||||
/// If rate limiting is disabled on provided `token_type`, this function will always succeed.
|
||||
pub fn consume(&self, tokens: u64, token_type: TokenType) -> bool {
|
||||
self.inner.rate_limiter.consume(tokens, token_type)
|
||||
}
|
||||
|
||||
/// Adds tokens of `token_type` to their respective bucket.
|
||||
///
|
||||
/// Can be used to *manually* add tokens to a bucket. Useful for reverting a
|
||||
/// `consume()` if needed.
|
||||
pub fn manual_replenish(&self, tokens: u64, token_type: TokenType) {
|
||||
self.inner.rate_limiter.manual_replenish(tokens, token_type)
|
||||
}
|
||||
|
||||
/// This function needs to be called every time there is an event on the
|
||||
/// FD provided by this object's `AsRawFd` trait implementation.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// If the rate limiter is disabled or is not blocked, an error is returned.
|
||||
pub fn event_handler(&self) -> Result<(), Error> {
|
||||
self.eventfd.read().map_err(Error::EventFdRead).map(|_| ())
|
||||
}
|
||||
|
||||
/// Returns whether this rate limiter is blocked.
|
||||
///
|
||||
/// The limiter 'blocks' when a `consume()` operation fails because there was not enough
|
||||
/// budget for it.
|
||||
/// An event will be generated on the exported FD when the limiter 'unblocks'.
|
||||
pub fn is_blocked(&self) -> bool {
|
||||
self.inner.rate_limiter.is_blocked()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for RateLimiterGroupHandle {
|
||||
fn clone(&self) -> Self {
|
||||
RateLimiterGroupHandle::new(self.inner.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for RateLimiterGroupHandle {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.eventfd.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RateLimiterGroupHandle {
|
||||
fn drop(&mut self) {
|
||||
let mut handles = self.inner.handles.lock().unwrap();
|
||||
let index = handles
|
||||
.iter()
|
||||
.position(|handle| handle.as_raw_fd() == self.eventfd.as_raw_fd())
|
||||
.expect("RateLimiterGroupHandle must be subscribed to RateLimiterGroup");
|
||||
handles.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
struct RateLimiterGroupInner {
|
||||
id: String,
|
||||
rate_limiter: RateLimiter,
|
||||
handles: Mutex<Vec<Arc<EventFd>>>,
|
||||
}
|
||||
|
||||
/// A RateLimiterGroup is an extension of RateLimiter that enables rate-limiting
|
||||
/// the aggregate io consumption of multiple consumers.
|
||||
pub struct RateLimiterGroup {
|
||||
inner: Arc<RateLimiterGroupInner>,
|
||||
epoll_file: File,
|
||||
kill_evt: EventFd,
|
||||
epoll_thread: Option<thread::JoinHandle<()>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u64)]
|
||||
enum EpollDispatch {
|
||||
Kill = 1,
|
||||
Unblocked = 2,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl From<u64> for EpollDispatch {
|
||||
fn from(v: u64) -> Self {
|
||||
use EpollDispatch::*;
|
||||
match v {
|
||||
1 => Kill,
|
||||
2 => Unblocked,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RateLimiterGroup {
|
||||
/// Create a new RateLimiterGroup.
|
||||
pub fn new(
|
||||
id: &str,
|
||||
bytes_total_capacity: u64,
|
||||
bytes_one_time_burst: u64,
|
||||
bytes_complete_refill_time_ms: u64,
|
||||
ops_total_capacity: u64,
|
||||
ops_one_time_burst: u64,
|
||||
ops_complete_refill_time_ms: u64,
|
||||
) -> result::Result<Self, Error> {
|
||||
let rate_limiter = RateLimiter::new(
|
||||
bytes_total_capacity,
|
||||
bytes_one_time_burst,
|
||||
bytes_complete_refill_time_ms,
|
||||
ops_total_capacity,
|
||||
ops_one_time_burst,
|
||||
ops_complete_refill_time_ms,
|
||||
)
|
||||
.map_err(Error::RateLimiter)?;
|
||||
|
||||
let epoll_fd = epoll::create(true).map_err(Error::Epoll)?;
|
||||
let kill_evt = EventFd::new(0).map_err(Error::EventFd)?;
|
||||
|
||||
epoll::ctl(
|
||||
epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
kill_evt.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Kill as u64),
|
||||
)
|
||||
.map_err(Error::Epoll)?;
|
||||
|
||||
epoll::ctl(
|
||||
epoll_fd,
|
||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
||||
rate_limiter.as_raw_fd(),
|
||||
epoll::Event::new(epoll::Events::EPOLLIN, EpollDispatch::Unblocked as u64),
|
||||
)
|
||||
.map_err(Error::Epoll)?;
|
||||
|
||||
// Use 'File' to enforce closing on 'epoll_fd'
|
||||
// SAFETY: epoll_fd is valid
|
||||
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
|
||||
|
||||
Ok(Self {
|
||||
inner: Arc::new(RateLimiterGroupInner {
|
||||
id: id.to_string(),
|
||||
rate_limiter,
|
||||
handles: Mutex::new(Vec::new()),
|
||||
}),
|
||||
epoll_file,
|
||||
kill_evt,
|
||||
epoll_thread: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new RateLimiterGroupHandle.
|
||||
pub fn new_handle(&self) -> result::Result<RateLimiterGroupHandle, Error> {
|
||||
RateLimiterGroupHandle::new(self.inner.clone())
|
||||
}
|
||||
|
||||
/// Start a worker thread to broadcast an event to each RateLimiterGroupHandle
|
||||
/// when the RateLimiter becomes unblocked.
|
||||
pub fn start_thread(&mut self, exit_evt: EventFd) -> result::Result<(), Error> {
|
||||
let inner = self.inner.clone();
|
||||
let epoll_fd = self.epoll_file.as_raw_fd();
|
||||
thread::Builder::new()
|
||||
.name(format!("rate-limit-group-{}", inner.id))
|
||||
.spawn(move || {
|
||||
let res = std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
const EPOLL_EVENTS_LEN: usize = 2;
|
||||
|
||||
let mut events =
|
||||
[epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
|
||||
|
||||
loop {
|
||||
let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::Interrupted {
|
||||
continue;
|
||||
} else {
|
||||
return Err(Error::Epoll(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for event in events.iter().take(num_events) {
|
||||
let dispatch_event: EpollDispatch = event.data.into();
|
||||
match dispatch_event {
|
||||
EpollDispatch::Unknown => {
|
||||
let event = event.data;
|
||||
warn!("Unknown rate-limiter loop event: {}", event);
|
||||
}
|
||||
EpollDispatch::Unblocked => {
|
||||
inner.rate_limiter.event_handler().unwrap();
|
||||
let handles = inner.handles.lock().unwrap();
|
||||
for handle in handles.iter() {
|
||||
handle.write(1).map_err(Error::EventFdWrite)?
|
||||
}
|
||||
}
|
||||
EpollDispatch::Kill => {
|
||||
info!(
|
||||
"KILL_EVENT received, stopping rate-limit-group epoll loop"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
match res {
|
||||
Ok(res) => {
|
||||
if let Err(e) = res {
|
||||
error!("Error running rate-limit-group worker: {:?}", e);
|
||||
exit_evt.write(1).unwrap();
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
error!("rate-limit-group worker panicked");
|
||||
exit_evt.write(1).unwrap();
|
||||
}
|
||||
};
|
||||
})
|
||||
.map(|thread| self.epoll_thread.insert(thread))
|
||||
.map_err(Error::ThreadSpawn)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RateLimiterGroup {
|
||||
fn drop(&mut self) {
|
||||
self.kill_evt.write(1).unwrap();
|
||||
|
||||
if let Some(t) = self.epoll_thread.take() {
|
||||
if let Err(e) = t.join() {
|
||||
error!("Error joining thread: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::RateLimiterGroupHandle;
|
||||
use crate::{group::RateLimiterGroup, TokenBucket, TokenType, REFILL_TIMER_INTERVAL_MS};
|
||||
use std::{os::fd::AsRawFd, thread, time::Duration};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
impl RateLimiterGroupHandle {
|
||||
pub fn bandwidth(&self) -> Option<TokenBucket> {
|
||||
let guard = self.inner.rate_limiter.inner.lock().unwrap();
|
||||
guard.bandwidth.clone()
|
||||
}
|
||||
|
||||
pub fn ops(&self) -> Option<TokenBucket> {
|
||||
let guard = self.inner.rate_limiter.inner.lock().unwrap();
|
||||
guard.ops.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_new() {
|
||||
let l = RateLimiterGroup::new("test", 1000, 1001, 1002, 1003, 1004, 1005).unwrap();
|
||||
let h = l.new_handle().unwrap();
|
||||
let bw = h.bandwidth().unwrap();
|
||||
assert_eq!(bw.capacity(), 1000);
|
||||
assert_eq!(bw.one_time_burst(), 1001);
|
||||
assert_eq!(bw.refill_time_ms(), 1002);
|
||||
assert_eq!(bw.budget(), 1000);
|
||||
|
||||
let ops = h.ops().unwrap();
|
||||
assert_eq!(ops.capacity(), 1003);
|
||||
assert_eq!(ops.one_time_burst(), 1004);
|
||||
assert_eq!(ops.refill_time_ms(), 1005);
|
||||
assert_eq!(ops.budget(), 1003);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_manual_replenish() {
|
||||
// rate limiter with limit of 1000 bytes/s and 1000 ops/s
|
||||
let l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
|
||||
let h = l.new_handle().unwrap();
|
||||
|
||||
// consume 123 bytes
|
||||
assert!(h.consume(123, TokenType::Bytes));
|
||||
h.manual_replenish(23, TokenType::Bytes);
|
||||
{
|
||||
let bytes_tb = h.bandwidth().unwrap();
|
||||
assert_eq!(bytes_tb.budget(), 900);
|
||||
}
|
||||
// consume 123 ops
|
||||
assert!(h.consume(123, TokenType::Ops));
|
||||
h.manual_replenish(23, TokenType::Ops);
|
||||
{
|
||||
let bytes_tb = h.ops().unwrap();
|
||||
assert_eq!(bytes_tb.budget(), 900);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_bandwidth() {
|
||||
// rate limiter with limit of 1000 bytes/s
|
||||
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 0, 0, 0).unwrap();
|
||||
l.start_thread(EventFd::new(0).unwrap()).unwrap();
|
||||
|
||||
let h = l.new_handle().unwrap();
|
||||
|
||||
// limiter should not be blocked
|
||||
assert!(!h.is_blocked());
|
||||
// raw FD for this disabled should be valid
|
||||
assert!(h.as_raw_fd() > 0);
|
||||
|
||||
// ops/s limiter should be disabled so consume(whatever) should work
|
||||
assert!(h.consume(u64::max_value(), TokenType::Ops));
|
||||
|
||||
// do full 1000 bytes
|
||||
assert!(h.consume(1000, TokenType::Bytes));
|
||||
// try and fail on another 100
|
||||
assert!(!h.consume(100, TokenType::Bytes));
|
||||
// since consume failed, limiter should be blocked now
|
||||
assert!(h.is_blocked());
|
||||
// wait half the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// limiter should still be blocked
|
||||
assert!(h.is_blocked());
|
||||
// wait the other half of the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// the timer_fd should have an event on it by now
|
||||
assert!(h.event_handler().is_ok());
|
||||
// limiter should now be unblocked
|
||||
assert!(!h.is_blocked());
|
||||
// try and succeed on another 100 bytes this time
|
||||
assert!(h.consume(100, TokenType::Bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_ops() {
|
||||
// rate limiter with limit of 1000 ops/s
|
||||
let mut l = RateLimiterGroup::new("test", 0, 0, 0, 1000, 0, 1000).unwrap();
|
||||
l.start_thread(EventFd::new(0).unwrap()).unwrap();
|
||||
|
||||
let h = l.new_handle().unwrap();
|
||||
|
||||
// limiter should not be blocked
|
||||
assert!(!h.is_blocked());
|
||||
// raw FD for this disabled should be valid
|
||||
assert!(h.as_raw_fd() > 0);
|
||||
|
||||
// bytes/s limiter should be disabled so consume(whatever) should work
|
||||
assert!(h.consume(u64::max_value(), TokenType::Bytes));
|
||||
|
||||
// do full 1000 ops
|
||||
assert!(h.consume(1000, TokenType::Ops));
|
||||
// try and fail on another 100
|
||||
assert!(!h.consume(100, TokenType::Ops));
|
||||
// since consume failed, limiter should be blocked now
|
||||
assert!(h.is_blocked());
|
||||
// wait half the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// limiter should still be blocked
|
||||
assert!(h.is_blocked());
|
||||
// wait the other half of the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// the timer_fd should have an event on it by now
|
||||
assert!(h.event_handler().is_ok());
|
||||
// limiter should now be unblocked
|
||||
assert!(!h.is_blocked());
|
||||
// try and succeed on another 100 ops this time
|
||||
assert!(h.consume(100, TokenType::Ops));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_full() {
|
||||
// rate limiter with limit of 1000 bytes/s and 1000 ops/s
|
||||
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
|
||||
l.start_thread(EventFd::new(0).unwrap()).unwrap();
|
||||
|
||||
let h = l.new_handle().unwrap();
|
||||
|
||||
// limiter should not be blocked
|
||||
assert!(!h.is_blocked());
|
||||
// raw FD for this disabled should be valid
|
||||
assert!(h.as_raw_fd() > 0);
|
||||
|
||||
// do full 1000 bytes
|
||||
assert!(h.consume(1000, TokenType::Ops));
|
||||
// do full 1000 bytes
|
||||
assert!(h.consume(1000, TokenType::Bytes));
|
||||
// try and fail on another 100 ops
|
||||
assert!(!h.consume(100, TokenType::Ops));
|
||||
// try and fail on another 100 bytes
|
||||
assert!(!h.consume(100, TokenType::Bytes));
|
||||
// since consume failed, limiter should be blocked now
|
||||
assert!(h.is_blocked());
|
||||
// wait half the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// limiter should still be blocked
|
||||
assert!(h.is_blocked());
|
||||
// wait the other half of the timer period
|
||||
thread::sleep(Duration::from_millis(REFILL_TIMER_INTERVAL_MS / 2));
|
||||
// the timer_fd should have an event on it by now
|
||||
assert!(h.event_handler().is_ok());
|
||||
// limiter should now be unblocked
|
||||
assert!(!h.is_blocked());
|
||||
// try and succeed on another 100 ops this time
|
||||
assert!(h.consume(100, TokenType::Ops));
|
||||
// try and succeed on another 100 bytes this time
|
||||
assert!(h.consume(100, TokenType::Bytes));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_overconsumption() {
|
||||
// initialize the rate limiter
|
||||
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
|
||||
l.start_thread(EventFd::new(0).unwrap()).unwrap();
|
||||
|
||||
let h = l.new_handle().unwrap();
|
||||
|
||||
// try to consume 2.5x the bucket size
|
||||
// we are "borrowing" 1.5x the bucket size in tokens since
|
||||
// the bucket is full
|
||||
assert!(h.consume(2500, TokenType::Bytes));
|
||||
|
||||
// check that even after a whole second passes, the rate limiter
|
||||
// is still blocked
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
assert!(h.is_blocked());
|
||||
|
||||
// after 1.5x the replenish time has passed, the rate limiter
|
||||
// is available again
|
||||
thread::sleep(Duration::from_millis(500));
|
||||
assert!(h.event_handler().is_ok());
|
||||
assert!(!h.is_blocked());
|
||||
|
||||
// reset the rate limiter
|
||||
let mut l = RateLimiterGroup::new("test", 1000, 0, 1000, 1000, 0, 1000).unwrap();
|
||||
l.start_thread(EventFd::new(0).unwrap()).unwrap();
|
||||
|
||||
let h = l.new_handle().unwrap();
|
||||
// try to consume 1.5x the bucket size
|
||||
// we are "borrowing" 1.5x the bucket size in tokens since
|
||||
// the bucket is full, should arm the timer to 0.5x replenish
|
||||
// time, which is 500 ms
|
||||
assert!(h.consume(1500, TokenType::Bytes));
|
||||
|
||||
// check that after more than the minimum refill time,
|
||||
// the rate limiter is still blocked
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
assert!(h.is_blocked());
|
||||
|
||||
// try to consume some tokens, which should fail as the timer
|
||||
// is still active
|
||||
assert!(!h.consume(100, TokenType::Bytes));
|
||||
assert!(h.is_blocked());
|
||||
|
||||
// check that after the minimum refill time, the timer was not
|
||||
// overwritten and the rate limiter is still blocked from the
|
||||
// borrowing we performed earlier
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
assert!(h.is_blocked());
|
||||
assert!(!h.consume(100, TokenType::Bytes));
|
||||
|
||||
// after waiting out the full duration, rate limiter should be
|
||||
// available again
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
assert!(h.event_handler().is_ok());
|
||||
assert!(!h.is_blocked());
|
||||
assert!(h.consume(100, TokenType::Bytes));
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,9 @@ use std::sync::Mutex;
|
||||
use std::time::{Duration, Instant};
|
||||
use vmm_sys_util::timerfd::TimerFd;
|
||||
|
||||
/// Module for group rate limiting.
|
||||
pub mod group;
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Describes the errors that may occur while handling rate limiter events.
|
||||
pub enum Error {
|
||||
|
||||
267
release-notes.md
267
release-notes.md
@@ -1,3 +1,20 @@
|
||||
- [v38.0](#v380)
|
||||
- [Group Rate Limiter on Block Devices](#group-rate-limiter-on-block-devices)
|
||||
- [CPU Pinning Support for Block Device Worker Thread](#cpu-pinning-support-for-block-device-worker-thread)
|
||||
- [Optimized Boot Time with Parallel Memory Prefault](#optimized-boot-time-with-parallel-memory-prefault)
|
||||
- [New 'debug-console' Device](#new-debug-console-device)
|
||||
- [Improved VFIO Device Support](#improved-vfio-device-support)
|
||||
- [Extended CPU Affinity Support](#extended-cpu-affinity-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v37.0](#v370)
|
||||
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
|
||||
- [Multiple PCI segments Support for 32-bit VFIO devices](#multiple-pci-segments-support-for-32-bit-vfio-devices)
|
||||
- [Configurable Named TAP Devices](#configurable-named-tap-devices)
|
||||
- [TTY Output from Both Serial Device and Virtio Console](#tty-output-from-both-serial-device-and-virtio-console)
|
||||
- [Faster VM Restoration from Snapshots](#faster-vm-restoration-from-snapshots)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v36.0](#v360)
|
||||
- [Command Line Changes](#command-line-changes)
|
||||
- [Enabled Features Reported via API Endpoint and CLI](#enabled-features-reported-via-api-endpoint-and-cli)
|
||||
@@ -6,31 +23,31 @@
|
||||
- [Unix Socket Backend for Serial Port](#unix-socket-backend-for-serial-port)
|
||||
- [AIO Backend for Block Devices](#aio-backend-for-block-devices)
|
||||
- [Documentation Improvements](#documentation-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v35.0](#v350)
|
||||
- [`virtio-vsock` Support for Linux Guest Kernel v6.3+](#virtio-vsock-support-for-linux-guest-kernel-v63)
|
||||
- [User Specified Serial Number for `virtio-block`](#user-specified-serial-number-for-virtio-block)
|
||||
- [vCPU TSC Frequency Included in Migration State](#vcpu-tsc-frequency-included-in-migration-state)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v34.0](#v340)
|
||||
- [Paravirtualised Panic Device Support](#paravirtualised-panic-device-support)
|
||||
- [Improvements to VM Core Dump](#improvements-to-vm-core-dump)
|
||||
- [QCOW2 Support for Backing Files](#qcow2-support-for-backing-files)
|
||||
- [Minimum Host Kernel Bump](#minimum-host-kernel-bump)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v33.0](#v330)
|
||||
- [D-Bus based API](#d-bus-based-api)
|
||||
- [Expose Host CPU Cache Details for AArch64](#expose-host-cpu-cache-details-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v32.0](#v320)
|
||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||
- [API Changes](#api-changes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v31.1](#v311)
|
||||
- [v31.0](#v310)
|
||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||
@@ -38,15 +55,15 @@
|
||||
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
||||
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
||||
- [Documentation Improvements](#documentation-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v30.0](#v300)
|
||||
- [Command Line Changes for Reduced Binary Size](#command-line-changes-for-reduced-binary-size)
|
||||
- [Basic vfio-user Server Support](#basic-vfio-user-server-support)
|
||||
- [Heap Profiling Support](#heap-profiling-support)
|
||||
- [Documentation Improvements](#documentation-improvements-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Contributors](#contributors-8)
|
||||
- [v28.2](#v282)
|
||||
- [v29.0](#v290)
|
||||
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
||||
@@ -56,20 +73,20 @@
|
||||
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
||||
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
||||
- [TCP Offload Control](#tcp-offload-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Removals](#removals)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Contributors](#contributors-9)
|
||||
- [v28.1](#v281)
|
||||
- [v28.0](#v280)
|
||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||
- [Long Term Support (LTS) Release](#long-term-support-lts-release)
|
||||
- [Long Term Support (LTS) Release](#long-term-support-lts-release-1)
|
||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v27.0](#v270)
|
||||
- [Community Engagement](#community-engagement)
|
||||
- [Prebuilt Packages](#prebuilt-packages)
|
||||
@@ -78,41 +95,41 @@
|
||||
- [Simplified Build Feature Flags](#simplified-build-feature-flags)
|
||||
- [Asynchronous Kernel Loading](#asynchronous-kernel-loading)
|
||||
- [GDB Support for AArch64](#gdb-support-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Contributors](#contributors-11)
|
||||
- [v26.0](#v260)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
||||
- [Deprecations](#deprecations-2)
|
||||
- [Removals](#removals-2)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v25.0](#v250)
|
||||
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
||||
- [VM "Coredump" Support](#vm-coredump-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-13)
|
||||
- [Removals](#removals-3)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Contributors](#contributors-13)
|
||||
- [v24.0](#v240)
|
||||
- [Bypass Mode for `virtio-iommu`](#bypass-mode-for-virtio-iommu)
|
||||
- [Ensure Identifiers Uniqueness](#ensure-identifiers-uniqueness)
|
||||
- [Sparse Mmap support](#sparse-mmap-support)
|
||||
- [Expose Platform Serial Number](#expose-platform-serial-number)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-12)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-14)
|
||||
- [Notable Improvements](#notable-improvements)
|
||||
- [Deprecations](#deprecations-3)
|
||||
- [New on the Website](#new-on-the-website)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Contributors](#contributors-14)
|
||||
- [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-13)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
||||
- [Deprecations](#deprecations-4)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Contributors](#contributors-15)
|
||||
- [v22.1](#v221)
|
||||
- [v22.0](#v220)
|
||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||
@@ -123,13 +140,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-14)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-16)
|
||||
- [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-15)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-17)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
@@ -138,8 +155,8 @@
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-16)
|
||||
- [Notable bug fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-18)
|
||||
- [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)
|
||||
@@ -147,8 +164,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-17)
|
||||
- [Contributors](#contributors-17)
|
||||
- [Notable bug fixes](#notable-bug-fixes-19)
|
||||
- [Contributors](#contributors-19)
|
||||
- [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)
|
||||
@@ -158,23 +175,23 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-18)
|
||||
- [Notable bug fixes](#notable-bug-fixes-20)
|
||||
- [Contributors](#contributors-20)
|
||||
- [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-19)
|
||||
- [Contributors](#contributors-19)
|
||||
- [Notable bug fixes](#notable-bug-fixes-21)
|
||||
- [Contributors](#contributors-21)
|
||||
- [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-20)
|
||||
- [Notable bug fixes](#notable-bug-fixes-22)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-20)
|
||||
- [Contributors](#contributors-22)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
@@ -182,7 +199,7 @@
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations-5)
|
||||
- [Contributors](#contributors-21)
|
||||
- [Contributors](#contributors-23)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -192,7 +209,7 @@
|
||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||
- [Block device rate limiting](#block-device-rate-limiting)
|
||||
- [Deprecations](#deprecations-6)
|
||||
- [Contributors](#contributors-22)
|
||||
- [Contributors](#contributors-24)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -200,13 +217,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-23)
|
||||
- [Contributors](#contributors-25)
|
||||
- [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-24)
|
||||
- [Contributors](#contributors-26)
|
||||
- [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)
|
||||
@@ -218,15 +235,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-21)
|
||||
- [Contributors](#contributors-25)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-23)
|
||||
- [Contributors](#contributors-27)
|
||||
- [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-22)
|
||||
- [Contributors](#contributors-26)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-24)
|
||||
- [Contributors](#contributors-28)
|
||||
- [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)
|
||||
@@ -239,17 +256,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-23)
|
||||
- [Contributors](#contributors-27)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-25)
|
||||
- [Contributors](#contributors-29)
|
||||
- [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-24)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-26)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-28)
|
||||
- [Contributors](#contributors-30)
|
||||
- [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)
|
||||
@@ -259,14 +276,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-29)
|
||||
- [Contributors](#contributors-31)
|
||||
- [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-30)
|
||||
- [Contributors](#contributors-32)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -274,7 +291,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-31)
|
||||
- [Contributors](#contributors-33)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -283,7 +300,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-32)
|
||||
- [Contributors](#contributors-34)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -310,6 +327,138 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v38.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v38.0. The following user visible changes have been made:
|
||||
|
||||
### Group Rate Limiter on Block Devices
|
||||
|
||||
Users now can throttle a group of block devices with the new
|
||||
`--rate-limiter-group` option. Details can be found from the [I/O
|
||||
Throttling documentation](docs/io_throttling.md)
|
||||
|
||||
### CPU Pinning Support for Block Device Worker Thread
|
||||
|
||||
Users now have the option to pin virt-queue threads for block devices
|
||||
to specific host cpus.
|
||||
|
||||
### Optimized Boot Time with Parallel Memory Prefault
|
||||
|
||||
The boot time with `prefault` option enabled is optimized via parallel
|
||||
memory prefault.
|
||||
|
||||
### New 'debug-console' Device
|
||||
|
||||
A 'debug-console' device is added to provide a user-configurable debug
|
||||
port for logging guest information. Details can be found from the [Debug
|
||||
IO Ports documentation](docs/debug-port.md).
|
||||
|
||||
### Improved VFIO Device Support
|
||||
|
||||
All non-emulated MMIO regions of VFIO devices are now mapped to the VFIO
|
||||
container, allowing PCIe P2P between all VFIO devices on the same
|
||||
VM. This is required for a wide variety of multi-GPU workloads involving
|
||||
GPUDirect P2P (DMA between two GPUs), GPUDirect RDMA (DMA between a GPU
|
||||
and an IB device).
|
||||
|
||||
### Extended CPU Affinity Support
|
||||
|
||||
Users now can set the vcpu affinity to a host CPU with index larger
|
||||
than 255.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Enable HTT flag to avoid crashing cpu topology enumeration software
|
||||
such as hwloc in the guest (#6146)
|
||||
* Fix several security advisories from dependencies (#6134, #6141)
|
||||
* Handle non-power-of-two CPU topology properly (#6062)
|
||||
* Various bug fixes around `virtio-vsock`(#6080, #6091, #6095)
|
||||
* Enable nested virtualization on AMD if supported (#6106)
|
||||
* Align VFIO devices PCI BARs naturally (#6196)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Daniel Farina <daniel@ubicloud.com>
|
||||
* Jinank Jain <jinankjain@microsoft.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Peteris Rudzusiks <rye@stripe.com>
|
||||
* Philipp Schuster <philipp.schuster@cyberus-technology.de>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Sean Banko <sbanko@crusoeenergy.com>
|
||||
* Thomas Barrett <tbarrett@crusoeenergy.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Yi Wang <foxywang@tencent.com>
|
||||
* acarp <acarp@crusoeenergy.com>
|
||||
|
||||
# v37.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v37.0. The following user visible changes have been made:
|
||||
|
||||
### Long Term Support (LTS) Release
|
||||
|
||||
This release is a LTS release. Point releases for bug fixes will be made
|
||||
for the next 18 months; live migration and live upgrade will be
|
||||
supported between the point releases of the LTS.
|
||||
|
||||
### Multiple PCI segments Support for 32-bit VFIO devices
|
||||
|
||||
Now VFIO devices with 32-bit memory BARs can be attached to non-zero PCI
|
||||
segments on the guest, allowing users to have more 32-bit devices and
|
||||
assign such devices to appropriate NUMA nodes for better performance.
|
||||
|
||||
### Configurable Named TAP Devices
|
||||
|
||||
Named TAP devices now accepts IP configuration from users, such as IP
|
||||
and MAC address, as long as the named TAP device is created by Cloud
|
||||
Hypervisor (e.g. not existing TAP devices).
|
||||
|
||||
### TTY Output from Both Serial Device and Virtio Console
|
||||
|
||||
Now legacy serial device and virtio console can be set as TTY mode as
|
||||
the same time. This allows users to capture early boot logs with the
|
||||
legacy serial device without losing performance benefits of using
|
||||
virtio-console, when appropriate kernel configuration is used (such as
|
||||
using kernel command-line `console=hvc0 earlyprintk=ttyS0` on x86).
|
||||
|
||||
### Faster VM Restoration from Snapshots
|
||||
|
||||
The speed of VM restoration from snapshots is improved with a better
|
||||
implementation of deserializing JSON files.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Fix aio backend behavior for block devices when writeback cache
|
||||
disabled (#5930)
|
||||
* Fix PvPanic device PCI BAR alignment (#5956)
|
||||
* Bug fix to OpenAPI specification file (#5967)
|
||||
* Error out early for live migration when TDX is enabled (#6025)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Jinank Jain <jinankjain@microsoft.com>
|
||||
* Markus Sütter <markus.suetter@secunet.com>
|
||||
* Michael Zhao <michael.zhao@arm.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Rui Chang <rui.chang@arm.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Thomas Barrett <tbarrett@crusoeenergy.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
* Yi Wang <foxywang@tencent.com>
|
||||
* Yong He <alexyonghe@tencent.com>
|
||||
|
||||
# v36.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
# When changing this file don't forget to update the tag name in the
|
||||
# .github/workflows/docker-image.yaml file if doing multiple per day
|
||||
|
||||
FROM ubuntu:20.04 as dev
|
||||
FROM ubuntu:22.04 as dev
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.67.1"
|
||||
ARG RUST_TOOLCHAIN="1.70.0"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -43,7 +43,6 @@ RUN apt-get update \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
: '
|
||||
This script checks if an image is compatible with Cloud Hypervisor.
|
||||
At first, it detects the image type(raw or qcow2),
|
||||
@@ -8,8 +8,6 @@
|
||||
a message about the compatibility of the image.
|
||||
'
|
||||
|
||||
|
||||
|
||||
usage="$(basename "$0") [-h] -f -w -- program to check Cloud Hypervisor compatible image
|
||||
|
||||
where:
|
||||
@@ -18,12 +16,11 @@ where:
|
||||
-w directory to be used for temporary files"
|
||||
|
||||
function check_command {
|
||||
if ! command -v $1 &> /dev/null
|
||||
then
|
||||
echo "Command $1 could not be found"
|
||||
if ! command -v "$1" &>/dev/null; then
|
||||
echo "Command $1 could not be found"
|
||||
exit 1
|
||||
fi
|
||||
};
|
||||
}
|
||||
|
||||
function check_if_root {
|
||||
if [ "$EUID" -ne 0 ]; then
|
||||
@@ -31,27 +28,32 @@ function check_if_root {
|
||||
exit 1
|
||||
fi
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
check_if_root
|
||||
working_dir=""
|
||||
while getopts ':hf:w:' option; do
|
||||
case "$option" in
|
||||
h) echo "$usage"
|
||||
exit
|
||||
;;
|
||||
f) file_name=$OPTARG
|
||||
;;
|
||||
w) working_dir=$OPTARG
|
||||
;;
|
||||
:) printf "missing argument for -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
\?) printf "illegal option: -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
h)
|
||||
echo "$usage"
|
||||
exit
|
||||
;;
|
||||
f)
|
||||
file_name=$OPTARG
|
||||
;;
|
||||
w)
|
||||
working_dir=$OPTARG
|
||||
;;
|
||||
:)
|
||||
printf "missing argument for -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
\?)
|
||||
printf "illegal option: -%s\n" "$OPTARG" >&2
|
||||
echo "$usage" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
@@ -59,67 +61,64 @@ shift $((OPTIND - 1))
|
||||
|
||||
if [ -z "${file_name}" ]; then
|
||||
echo "You must provide the image file name"
|
||||
exit 1
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f ${file_name} ]]; then
|
||||
echo "File ${file_name} does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file_abs_path=`readlink -m ${file_name}`
|
||||
file_abs_path=$(readlink -m "${file_name}")
|
||||
if [[ "${working_dir}" != "" && ! -d "${working_dir}" ]]; then
|
||||
echo "Directory ${working_dir} does not exist"
|
||||
exit 1
|
||||
elif [[ "${working_dir}" == "" ]]; then
|
||||
working_dir=`mktemp -d`
|
||||
working_dir=$(mktemp -d)
|
||||
tmp_created=1
|
||||
else
|
||||
working_dir=`readlink -m ${working_dir}`
|
||||
working_dir=$(readlink -m "${working_dir}")
|
||||
fi
|
||||
|
||||
#get file extension and image type
|
||||
extension="${file_name##*.}"
|
||||
filename="${file_name%.*}"
|
||||
dest_file=${working_dir}/${filename}.raw
|
||||
image_type=$(qemu-img info ${file_abs_path} | grep 'file format:' | awk '{ print $3 }')
|
||||
image_type=$(qemu-img info "${file_abs_path}" | grep 'file format:' | awk '{ print $3 }')
|
||||
echo "Image type detected as ${image_type}"
|
||||
|
||||
|
||||
if [[ "${image_type}" == "raw" ]]; then
|
||||
dest_file=${file_abs_path}
|
||||
dest_file=${file_abs_path}
|
||||
elif [[ "$image_type" == "qcow2" ]]; then
|
||||
if lsmod | grep "nbd" &> /dev/null ; then
|
||||
if lsmod | grep "nbd" &>/dev/null; then
|
||||
echo "Module nbd is loaded!"
|
||||
else
|
||||
echo "Module nbd is not loaded. Trying to load the module"
|
||||
modprobe nbd max_part=8
|
||||
if [ $? != 0 ]; then
|
||||
|
||||
if ! modprobe nbd max_part=8; then
|
||||
echo "failed to load nbd module. Exiting"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
check_command qemu-img
|
||||
dest_file=/dev/nbd0
|
||||
qemu-nbd --connect=${dest_file} ${file_abs_path} --read-only
|
||||
qemu-nbd --connect=${dest_file} "${file_abs_path}" --read-only
|
||||
fi
|
||||
|
||||
check_command blkid
|
||||
#get part info
|
||||
part_type=$(blkid -o value -s PTTYPE ${dest_file})
|
||||
part_type=$(blkid -o value -s PTTYPE "${dest_file}")
|
||||
|
||||
check_command partx
|
||||
nr_partitions=`partx -g ${dest_file} | wc -l`
|
||||
nr_partitions=$(partx -g "${dest_file}" | wc -l)
|
||||
|
||||
check_command fdisk
|
||||
out=`fdisk -l ${dest_file} --bytes | grep -i -A ${nr_partitions} 'Device' | tail -n +2`
|
||||
out=$(fdisk -l "${dest_file}" --bytes | grep -i -A "${nr_partitions}" 'Device' | tail -n +2)
|
||||
|
||||
IFS='
|
||||
'
|
||||
i=0
|
||||
declare -A liness
|
||||
for x in $out ; do
|
||||
lines[$i]=$x
|
||||
i=$((i+1))
|
||||
declare -A lines
|
||||
for x in $out; do
|
||||
lines[$i]=$x
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
declare -A partitions
|
||||
@@ -127,89 +126,86 @@ IFS=' '
|
||||
i=0
|
||||
ROWS=${#lines[@]}
|
||||
|
||||
for line in "${lines[@]}";
|
||||
do
|
||||
j=0
|
||||
read -a str_arr <<< "$line"
|
||||
for val in "${str_arr[@]}";
|
||||
do
|
||||
if [[ "$val" != "*" ]]; then
|
||||
partitions[$i,$j]=$val
|
||||
j=$((j+1))
|
||||
fi
|
||||
done
|
||||
i=$((i+1))
|
||||
for line in "${lines[@]}"; do
|
||||
j=0
|
||||
read -a -r str_arr <<<"$line"
|
||||
for val in "${str_arr[@]}"; do
|
||||
if [[ "$val" != "*" ]]; then
|
||||
partitions[$i, $j]=$val
|
||||
j=$((j + 1))
|
||||
fi
|
||||
done
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
COLUMNS=$j
|
||||
COUNT=${#partitions[@]}
|
||||
START_ADDRESS_INDEX=1
|
||||
FILE_SYS_INDEX2=$((COLUMNS-1))
|
||||
FILE_SYS_INDEX1=$((COLUMNS-2))
|
||||
FILE_SYS_INDEX2=$((COLUMNS - 1))
|
||||
FILE_SYS_INDEX1=$((COLUMNS - 2))
|
||||
DEVICE_INDEX=0
|
||||
# Here we have all the partition info now lets mount and analyze the contents
|
||||
for ((i=0;i<ROWS;i++)) do
|
||||
if [[ "$part_type" == "gpt" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then
|
||||
for ((i = 0; i < ROWS; i++)); do
|
||||
if [[ "$part_type" == "gpt" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "filesystem" ]]; then
|
||||
echo "The image has GPT partitions"
|
||||
MOUNT_ROW=$i
|
||||
break
|
||||
elif [[ "$part_type" == "dos" && "${partitions[$i,${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i,${FILE_SYS_INDEX2}]}" == "" ]]; then
|
||||
break
|
||||
elif [[ "$part_type" == "dos" && "${partitions[$i, ${FILE_SYS_INDEX1}]}" == "Linux" && "${partitions[$i, ${FILE_SYS_INDEX2}]}" == "" ]]; then
|
||||
echo "The image has DOS partitions"
|
||||
MOUNT_ROW=$i
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
start_address=${partitions[${MOUNT_ROW},${START_ADDRESS_INDEX}]}
|
||||
offset=$((start_address*512))
|
||||
start_address=${partitions[${MOUNT_ROW}, ${START_ADDRESS_INDEX}]}
|
||||
offset=$((start_address * 512))
|
||||
|
||||
MOUNT_DIR=/mnt/clh-img-check/
|
||||
rm -rf ${MOUNT_DIR}
|
||||
mkdir ${MOUNT_DIR}
|
||||
if [[ "${image_type}" == "raw" ]]; then
|
||||
mount -o ro,loop,offset=$offset ${dest_file} ${MOUNT_DIR}
|
||||
mount -o ro,loop,offset=$offset "${dest_file}" ${MOUNT_DIR}
|
||||
elif [[ "${image_type}" == "qcow2" ]]; then
|
||||
mount -o ro ${partitions[${MOUNT_ROW},${DEVICE_INDEX}]} ${MOUNT_DIR}
|
||||
mount -o ro "${partitions[${MOUNT_ROW}, ${DEVICE_INDEX}]}" ${MOUNT_DIR}
|
||||
fi
|
||||
|
||||
CONFIG_DIR=${MOUNT_DIR}boot/
|
||||
if [[ "$part_type" == "dos" ]]; then
|
||||
CONFIG_DIR=${MOUNT_DIR}
|
||||
CONFIG_DIR=${MOUNT_DIR}
|
||||
fi
|
||||
|
||||
#check VIRTIO
|
||||
HAS_VIRTIO=1
|
||||
for conf_file in ${CONFIG_DIR}config*; do
|
||||
out=`grep -E "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" ${conf_file} | wc -l`
|
||||
for conf_file in "${CONFIG_DIR}"config*; do
|
||||
out=$(grep -cE "CONFIG_VIRTIO=y|CONFIG_VIRTIO_BLK=y|CONFIG_VIRTIO_BLK=m" "${conf_file}")
|
||||
if [[ "$out" != "2" ]]; then
|
||||
echo "VIRTIO not found"
|
||||
HAS_VIRTIO=0
|
||||
fi
|
||||
echo "VIRTIO not found"
|
||||
HAS_VIRTIO=0
|
||||
fi
|
||||
done
|
||||
|
||||
#clean up
|
||||
umount ${MOUNT_DIR}
|
||||
|
||||
if [[ "${tmp_created}" == "1" ]]; then
|
||||
rm -rf ${working_dir}
|
||||
rm -rf "${working_dir}"
|
||||
fi
|
||||
|
||||
if [[ "${image_type}" == "qcow2" ]];then
|
||||
qemu-nbd --disconnect ${dest_file} > /dev/null
|
||||
if [[ "${image_type}" == "qcow2" ]]; then
|
||||
qemu-nbd --disconnect "${dest_file}" >/dev/null
|
||||
fi
|
||||
|
||||
result=""
|
||||
if [[ "${part_type}" == "dos" ]]; then
|
||||
result="dos mode not supported"
|
||||
result="dos mode not supported"
|
||||
fi
|
||||
if [[ "${HAS_VIRTIO}" == "0" ]]; then
|
||||
if [[ "$result" != "" ]]; then
|
||||
result="${result},"
|
||||
fi
|
||||
result="$result VirtIO module not found in the image"
|
||||
if [[ "$result" != "" ]]; then
|
||||
result="${result},"
|
||||
fi
|
||||
result="$result VirtIO module not found in the image"
|
||||
fi
|
||||
if [[ "$result" == "" ]];then
|
||||
echo "No incompatibilities found"
|
||||
if [[ "$result" == "" ]]; then
|
||||
echo "No incompatibilities found"
|
||||
else
|
||||
echo "$result"
|
||||
echo "$result"
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
|
||||
@@ -22,26 +22,26 @@ build_edk2() {
|
||||
|
||||
# Prepare source code
|
||||
checkout_repo "$EDK2_DIR" "$EDK2_REPO" master "46b4606ba23498d3d0e66b53e498eb3d5d592586"
|
||||
pushd "$EDK2_DIR"
|
||||
pushd "$EDK2_DIR" || exit
|
||||
git submodule update --init
|
||||
popd
|
||||
popd || exit
|
||||
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"
|
||||
if [[ ! -f "$EDK2_DIR/.built" ||
|
||||
! -f "$EDK2_PLAT_DIR/.built" ||
|
||||
! -f "$ACPICA_DIR/.built" ]]; then
|
||||
pushd "$EDK2_BUILD_DIR" || exit
|
||||
# Build
|
||||
make -C acpica -j `nproc`
|
||||
make -C acpica -j "$(nproc)"
|
||||
# shellcheck disable=SC1091
|
||||
source edk2/edksetup.sh
|
||||
make -C edk2/BaseTools -j `nproc`
|
||||
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
|
||||
popd || exit
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
|
||||
rm -f /tmp/ubuntu-cloudinit.img
|
||||
@@ -6,4 +6,3 @@ mkdosfs -n CIDATA -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/local/network-config ::
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
# Copyright © 2020 Intel Corporation
|
||||
@@ -7,7 +7,7 @@
|
||||
CLI_NAME="Cloud Hypervisor"
|
||||
|
||||
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
|
||||
CTR_IMAGE_VERSION="20231012-0"
|
||||
CTR_IMAGE_VERSION="20231220-0"
|
||||
: "${CTR_IMAGE:=${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}}"
|
||||
|
||||
DOCKER_RUNTIME="docker"
|
||||
@@ -121,9 +121,7 @@ ensure_latest_ctr() {
|
||||
if [ "$CTR_IMAGE_VERSION" = "local" ]; then
|
||||
build_container
|
||||
else
|
||||
$DOCKER_RUNTIME pull "$CTR_IMAGE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
if ! $DOCKER_RUNTIME pull "$CTR_IMAGE"; then
|
||||
build_container
|
||||
fi
|
||||
|
||||
@@ -143,7 +141,8 @@ fix_dir_perms() {
|
||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||
--rm \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
"$CTR_IMAGE" \
|
||||
chown -R "$(id -u):$(id -g)" "$CTR_CLH_ROOT_DIR"
|
||||
|
||||
@@ -158,9 +157,9 @@ process_volumes_args() {
|
||||
return
|
||||
fi
|
||||
exported_volumes=""
|
||||
arr_vols=(${arg_vols//#/ })
|
||||
arr_vols=("${arg_vols//#/ }")
|
||||
for var in "${arr_vols[@]}"; do
|
||||
parts=(${var//:/ })
|
||||
parts=("${var//:/ }")
|
||||
if [[ ! -e "${parts[0]}" ]]; then
|
||||
echo "The volume ${parts[0]} does not exist."
|
||||
exit 1
|
||||
@@ -233,10 +232,10 @@ cmd_build() {
|
||||
"--debug") { build="debug"; } ;;
|
||||
"--release") { build="release"; } ;;
|
||||
"--runtime")
|
||||
shift
|
||||
DOCKER_RUNTIME="$1"
|
||||
export DOCKER_RUNTIME
|
||||
;;
|
||||
shift
|
||||
DOCKER_RUNTIME="$1"
|
||||
export DOCKER_RUNTIME
|
||||
;;
|
||||
"--libc")
|
||||
shift
|
||||
[[ "$1" =~ ^(musl|gnu)$ ]] ||
|
||||
@@ -282,11 +281,11 @@ cmd_build() {
|
||||
[ $build = "release" ] && cargo_args+=("--release")
|
||||
cargo_args+=(--target "$target")
|
||||
|
||||
# shellcheck disable=SC2153
|
||||
rustflags="$RUSTFLAGS"
|
||||
target_cc=""
|
||||
if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
|
||||
rustflags="$rustflags -C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
target_cc="musl-gcc"
|
||||
rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
|
||||
fi
|
||||
|
||||
$DOCKER_RUNTIME run \
|
||||
@@ -294,11 +293,12 @@ cmd_build() {
|
||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||
--rm \
|
||||
--volume $exported_device \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
"$CTR_IMAGE" \
|
||||
cargo build --all $features_build \
|
||||
cargo build --all "$features_build" \
|
||||
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
||||
"${cargo_args[@]}" && say "Binaries placed under $CLH_CARGO_TARGET/$target/$build"
|
||||
}
|
||||
@@ -313,7 +313,8 @@ cmd_clean() {
|
||||
--user "$(id -u):$(id -g)" \
|
||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||
--rm \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
"$CTR_IMAGE" \
|
||||
cargo clean \
|
||||
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
||||
@@ -362,7 +363,6 @@ cmd_tests() {
|
||||
hypervisor="$1"
|
||||
;;
|
||||
"--all") {
|
||||
cargo=true
|
||||
unit=true
|
||||
integration=true
|
||||
} ;;
|
||||
@@ -384,7 +384,7 @@ cmd_tests() {
|
||||
exported_device="/dev/mshv"
|
||||
fi
|
||||
|
||||
if [ ! -e "${exported_device}" ] ; then
|
||||
if [ ! -e "${exported_device}" ]; then
|
||||
die "${exported_device} does not exist on the system"
|
||||
fi
|
||||
|
||||
@@ -399,8 +399,7 @@ cmd_tests() {
|
||||
rustflags="$RUSTFLAGS"
|
||||
target_cc=""
|
||||
if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
|
||||
rustflags="$rustflags -C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
target_cc="musl-gcc"
|
||||
rustflags="$rustflags -C link-args=-Wl,-Bstatic -C link-args=-lc"
|
||||
fi
|
||||
|
||||
if [[ "$unit" = true ]]; then
|
||||
@@ -411,7 +410,8 @@ cmd_tests() {
|
||||
--device $exported_device \
|
||||
--device /dev/net/tun \
|
||||
--cap-add net_admin \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
@@ -430,12 +430,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -451,12 +453,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -472,12 +476,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -493,12 +499,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_windows_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -514,12 +522,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -535,12 +545,14 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_rate_limiter.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -556,13 +568,15 @@ cmd_tests() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--mount type=tmpfs,destination=/tmp \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env BUILD_TARGET="$target" \
|
||||
--env RUSTFLAGS="$rustflags" \
|
||||
--env TARGET_CC="$target_cc" \
|
||||
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
|
||||
--env AUTH_DOWNLOAD_TOKEN="$AUTH_DOWNLOAD_TOKEN" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
@@ -583,9 +597,9 @@ build_container() {
|
||||
|
||||
$DOCKER_RUNTIME build \
|
||||
--target dev \
|
||||
-t $CTR_IMAGE \
|
||||
-t "$CTR_IMAGE" \
|
||||
-f $BUILD_DIR/Dockerfile \
|
||||
--build-arg TARGETARCH=$TARGETARCH \
|
||||
--build-arg TARGETARCH="$TARGETARCH" \
|
||||
$BUILD_DIR
|
||||
}
|
||||
|
||||
@@ -645,7 +659,8 @@ cmd_shell() {
|
||||
--net="$CTR_CLH_NET" \
|
||||
--tmpfs /tmp:exec \
|
||||
--volume /dev:/dev \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" \
|
||||
${exported_volumes:+"$exported_volumes"} \
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--entrypoint bash \
|
||||
|
||||
92
scripts/gitlint/rules.py
Normal file
92
scripts/gitlint/rules.py
Normal file
@@ -0,0 +1,92 @@
|
||||
from gitlint.rules import LineRule, RuleViolation, CommitMessageTitle
|
||||
import re
|
||||
|
||||
|
||||
class TitleStartsWithComponent(LineRule):
|
||||
"""A rule to enforce valid commit message title
|
||||
|
||||
Valid title format:
|
||||
component1[, component2, componentN]: submodule: summary
|
||||
|
||||
Title should have at least one component
|
||||
Components are separated by comma+space: ", "
|
||||
Components are validated to be in valid_components
|
||||
Components list is ended by a colon
|
||||
Submodules are not validated
|
||||
|
||||
"""
|
||||
|
||||
# A rule MUST have a human friendly name
|
||||
name = "title-has-valid-component"
|
||||
|
||||
# A rule MUST have a *unique* id.
|
||||
# We recommend starting with UL (for User-defined Line-rule)
|
||||
id = "UL1"
|
||||
|
||||
# A line-rule MUST have a target (not required for CommitRules).
|
||||
target = CommitMessageTitle
|
||||
|
||||
def validate(self, line, _commit):
|
||||
valid_components = (
|
||||
'api_client',
|
||||
'arch',
|
||||
'block',
|
||||
'build',
|
||||
'ch-remote',
|
||||
'ci',
|
||||
'devices',
|
||||
'docs',
|
||||
'event_monitor',
|
||||
'fuzz',
|
||||
'github',
|
||||
'gitignore',
|
||||
'gitlint',
|
||||
'hypervisor',
|
||||
'Jenkinsfile',
|
||||
'main',
|
||||
'misc',
|
||||
'net_gen',
|
||||
'net_util',
|
||||
'option_parser',
|
||||
'pci',
|
||||
'performance-metrics',
|
||||
'rate_limiter',
|
||||
'README',
|
||||
'resources',
|
||||
'scripts',
|
||||
'serial_buffer',
|
||||
'test_data',
|
||||
'test_infra',
|
||||
'tests',
|
||||
'tpm',
|
||||
'tracer',
|
||||
'vhost_user_block',
|
||||
'vhost_user_net',
|
||||
'virtio-devices',
|
||||
'vm-allocator',
|
||||
'vm-device',
|
||||
'vmm',
|
||||
'vm-migration',
|
||||
'vm-virtio')
|
||||
|
||||
ptrn_title = re.compile(r'^(.+?):\s(.+)$')
|
||||
match = ptrn_title.match(line)
|
||||
|
||||
if not match:
|
||||
self.log.debug("Invalid commit title {}", line)
|
||||
return [RuleViolation(self.id, "Commit title does not comply with "
|
||||
"rule: 'component: change summary'")]
|
||||
components = match.group(1)
|
||||
summary = match.group(2)
|
||||
self.log.debug(f"\nComponents: {components}\nSummary: {summary}")
|
||||
|
||||
ptrn_components = re.compile(r',\s')
|
||||
components_list = re.split(ptrn_components, components)
|
||||
self.log.debug("components list: %s" % components_list)
|
||||
|
||||
for component in components_list:
|
||||
if component not in valid_components:
|
||||
return [RuleViolation(self.id,
|
||||
f"Invalid component: {component}, "
|
||||
"\nValid components are: {}".format(
|
||||
" ".join(valid_components)))]
|
||||
@@ -1,20 +1,20 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env 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 iproute2
|
||||
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
|
||||
apt-get source linux-image-unsigned-"$(uname -r)"
|
||||
pushd linux-azure*/drivers/vdpa/vdpa_sim/ || exit
|
||||
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
|
||||
make -C /lib/modules/"$(uname -r)"/build M="$PWD"
|
||||
sudo make -C /lib/modules/"$(uname -r)"/build M="$PWD" modules_install
|
||||
popd || exit
|
||||
sudo depmod -a
|
||||
sudo modprobe vdpa
|
||||
sudo modprobe vhost_vdpa
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
source $(dirname "$0")/common-aarch64.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
source "$(dirname "$0")"/common-aarch64.sh
|
||||
|
||||
WORKLOADS_LOCK="$WORKLOADS_DIR/integration_test.lock"
|
||||
|
||||
@@ -14,23 +16,23 @@ build_spdk_nvme() {
|
||||
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "ef8bcce58f3f02b79c0619a297e4f17e81e62b24"
|
||||
|
||||
if [ ! -f "$SPDK_DIR/.built" ]; then
|
||||
pushd $SPDK_DIR
|
||||
pushd "$SPDK_DIR" || exit
|
||||
git submodule update --init
|
||||
apt-get update
|
||||
sed -i "/grpcio/d" scripts/pkgdep/debian.sh
|
||||
./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
|
||||
chmod +x /usr/local/lib/python3.10/dist-packages/ninja/data/bin/ninja
|
||||
make -j "$(nproc)" || exit 1
|
||||
touch .built
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
cp -r "$WORKLOADS_DIR/spdk/python/spdk/" $SPDK_DEPLOY_DIR/
|
||||
cp -r "$WORKLOADS_DIR/spdk/python" $SPDK_DEPLOY_DIR/../
|
||||
}
|
||||
|
||||
@@ -38,36 +40,36 @@ 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"
|
||||
checkout_repo "$VIRTIOFSD_DIR" "$VIRTIOFSD_REPO" v1.8.0 "97ea7908fe7f9bc59916671a771bdcfaf4044b45"
|
||||
|
||||
if [ ! -f "$VIRTIOFSD_DIR/.built" ]; then
|
||||
pushd $VIRTIOFSD_DIR
|
||||
pushd "$VIRTIOFSD_DIR" || exit
|
||||
rm -rf target/
|
||||
time RUSTFLAGS="" TARGET_CC="" cargo build --release
|
||||
cp target/release/virtiofsd "$WORKLOADS_DIR/" || exit 1
|
||||
touch .built
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
}
|
||||
|
||||
update_workloads() {
|
||||
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
|
||||
cp scripts/sha1sums-aarch64 "$WORKLOADS_DIR"
|
||||
|
||||
BIONIC_OS_IMAGE_DOWNLOAD_NAME="bionic-server-cloudimg-arm64.img"
|
||||
BIONIC_OS_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
|
||||
BIONIC_OS_DOWNLOAD_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_DOWNLOAD_NAME"
|
||||
if [ ! -f "$BIONIC_OS_DOWNLOAD_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $BIONIC_OS_IMAGE_DOWNLOAD_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
BIONIC_OS_RAW_IMAGE_NAME="bionic-server-cloudimg-arm64.raw"
|
||||
BIONIC_OS_RAW_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$BIONIC_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $BIONIC_OS_IMAGE_DOWNLOAD_NAME $BIONIC_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
# Convert the raw image to qcow2 image to remove compressed blocks from the disk. Therefore letting the
|
||||
@@ -75,97 +77,109 @@ update_workloads() {
|
||||
BIONIC_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="bionic-server-cloudimg-arm64.qcow2"
|
||||
BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
if [ ! -f "$BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img convert -p -f raw -O qcow2 $BIONIC_OS_RAW_IMAGE_NAME $BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE || exit 1
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f raw -O qcow2 $BIONIC_OS_RAW_IMAGE_NAME "$BIONIC_OS_QCOW2_UNCOMPRESSED_IMAGE" || exit 1
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.raw"
|
||||
FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_RAW_IMAGE_DOWNLOAD_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
|
||||
FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_NAME"
|
||||
if [ ! -f "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME="focal-server-cloudimg-arm64-custom-20210929-0-backing.qcow2"
|
||||
FOCAL_OS_QCOW2_BACKING_FILE_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_QCOW2_BACKING_FILE_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img create -f qcow2 -b $FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE -F qcow2 $FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img create -f qcow2 -b "$FOCAL_OS_QCOW2_UNCOMPRESSED_IMAGE" -F qcow2 $FOCAL_OS_QCOW2_IMAGE_BACKING_FILE_NAME
|
||||
popd || exit
|
||||
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
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $JAMMY_OS_RAW_IMAGE_DOWNLOAD_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $JAMMY_OS_QCOW2_IMAGE_UNCOMPRESSED_DOWNLOAD_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $ALPINE_MINIROOTFS_URL -O $ALPINE_MINIROOTFS_TARBALL || exit 1
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $ALPINE_MINIROOTFS_URL -O "$ALPINE_MINIROOTFS_TARBALL" || exit 1
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
ALPINE_INITRAMFS_IMAGE="$WORKLOADS_DIR/alpine_initramfs.img"
|
||||
if [ ! -f "$ALPINE_INITRAMFS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
mkdir alpine-minirootfs
|
||||
tar xf "$ALPINE_MINIROOTFS_TARBALL" -C alpine-minirootfs
|
||||
cat > alpine-minirootfs/init <<-EOF
|
||||
cat >alpine-minirootfs/init <<-EOF
|
||||
#! /bin/sh
|
||||
mount -t devtmpfs dev /dev
|
||||
echo \$TEST_STRING > /dev/console
|
||||
poweroff -f
|
||||
EOF
|
||||
chmod +x alpine-minirootfs/init
|
||||
cd alpine-minirootfs
|
||||
cd alpine-minirootfs || exit
|
||||
find . -print0 |
|
||||
cpio --null --create --verbose --owner root:root --format=newc > "$ALPINE_INITRAMFS_IMAGE"
|
||||
popd
|
||||
cpio --null --create --verbose --owner root:root --format=newc >"$ALPINE_INITRAMFS_IMAGE"
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
sha1sum sha1sums-aarch64 --check
|
||||
if [ $? -ne 0 ]; then
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
|
||||
if ! sha1sum sha1sums-aarch64 --check; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
# Download Cloud Hypervisor binary from its last stable release
|
||||
LAST_RELEASE_VERSION="v34.0"
|
||||
LAST_RELEASE_VERSION="v36.0"
|
||||
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static-aarch64"
|
||||
CH_RELEASE_NAME="cloud-hypervisor-static-aarch64"
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
|
||||
chmod +x $CH_RELEASE_NAME
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
# Repeat a few times to workaround a random wget failure
|
||||
WGET_RETRY_MAX=10
|
||||
wget_retry=0
|
||||
|
||||
until [ "$wget_retry" -ge "$WGET_RETRY_MAX" ]; do
|
||||
time wget $CH_RELEASE_URL -O "$CH_RELEASE_NAME" && break
|
||||
wget_retry=$((wget_retry + 1))
|
||||
done
|
||||
|
||||
if [ $wget_retry -ge "$WGET_RETRY_MAX" ]; then
|
||||
exit 1
|
||||
else
|
||||
chmod +x $CH_RELEASE_NAME
|
||||
fi
|
||||
popd || exit
|
||||
|
||||
# Build custom kernel for guest VMs
|
||||
build_custom_linux
|
||||
@@ -186,22 +200,22 @@ update_workloads() {
|
||||
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
|
||||
MNT_DIR="mount_image"
|
||||
if [ ! -f "$BLK_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
fallocate -l 16M $BLK_IMAGE
|
||||
mkfs.ext4 -j $BLK_IMAGE
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
fallocate -l 16M "$BLK_IMAGE"
|
||||
mkfs.ext4 -j "$BLK_IMAGE"
|
||||
mkdir $MNT_DIR
|
||||
sudo mount -t ext4 $BLK_IMAGE $MNT_DIR
|
||||
sudo mount -t ext4 "$BLK_IMAGE" $MNT_DIR
|
||||
sudo bash -c "echo bar > $MNT_DIR/foo" || exit 1
|
||||
sudo umount $BLK_IMAGE
|
||||
sudo umount "$BLK_IMAGE"
|
||||
rm -r $MNT_DIR
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
SHARED_DIR="$WORKLOADS_DIR/shared_dir"
|
||||
if [ ! -d "$SHARED_DIR" ]; then
|
||||
mkdir -p $SHARED_DIR
|
||||
echo "foo" > "$SHARED_DIR/file1"
|
||||
echo "bar" > "$SHARED_DIR/file3" || exit 1
|
||||
mkdir -p "$SHARED_DIR"
|
||||
echo "foo" >"$SHARED_DIR/file1"
|
||||
echo "bar" >"$SHARED_DIR/file3" || exit 1
|
||||
fi
|
||||
|
||||
# Checkout and build SPDK NVMe
|
||||
@@ -219,12 +233,11 @@ if [[ "$hypervisor" = "mshv" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# lock the workloads folder to avoid parallel updating by different containers
|
||||
(
|
||||
echo "try to lock $WORKLOADS_DIR folder and update"
|
||||
flock -x 12 && update_workloads
|
||||
) 12>$WORKLOADS_LOCK
|
||||
) 12>"$WORKLOADS_LOCK"
|
||||
|
||||
# Check if there is any error in the execution of `update_workloads`.
|
||||
# If there is any error, then kill the shell. Otherwise the script will continue
|
||||
@@ -236,7 +249,7 @@ fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
cargo build --all --release --target $BUILD_TARGET
|
||||
cargo build --all --release --target "$BUILD_TARGET"
|
||||
|
||||
# Enable KSM with some reasonable parameters so that it won't take too long
|
||||
# for the memory to be merged between two processes.
|
||||
@@ -245,19 +258,19 @@ sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||
|
||||
# Both test_vfio and ovs-dpdk rely on hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=$(grep Hugepagesize /proc/meminfo | awk '{print $2}')
|
||||
PAGE_NUM=$((12288 * 1024 / HUGEPAGESIZE))
|
||||
echo "$PAGE_NUM" | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
time cargo test "common_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
time cargo test "common_parallel::$test_filter" --target "$BUILD_TARGET" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
# Run some tests in sequence since the result could be affected by other tests
|
||||
# running in parallel.
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test "common_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
|
||||
time cargo test "common_sequential::$test_filter" --target "$BUILD_TARGET" -- --test-threads=1 ${test_binary_args[*]}
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
@@ -265,7 +278,7 @@ fi
|
||||
|
||||
# Run all ACPI test cases
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test "aarch64_acpi::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
time cargo test "aarch64_acpi::$test_filter" --target "$BUILD_TARGET" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
@@ -273,14 +286,14 @@ fi
|
||||
|
||||
# Run all test cases related to live migration
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test "live_migration_parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
time cargo test "live_migration_parallel::$test_filter" --target "$BUILD_TARGET" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
if [ $RES -eq 0 ]; then
|
||||
time cargo test "live_migration_sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
|
||||
time cargo test "live_migration_sequential::$test_filter" --target "$BUILD_TARGET" -- --test-threads=1 ${test_binary_args[*]}
|
||||
RES=$?
|
||||
else
|
||||
exit $RES
|
||||
@@ -288,9 +301,9 @@ fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --features "dbus_api" --all --release --target $BUILD_TARGET
|
||||
cargo build --features "dbus_api" --all --release --target "$BUILD_TARGET"
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "dbus_api::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
time cargo test "dbus_api::$test_filter" --target "$BUILD_TARGET" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
@@ -12,45 +14,44 @@ process_common_args "$@"
|
||||
# For now these values are default for kvm
|
||||
test_features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
if [ "$hypervisor" = "mshv" ]; then
|
||||
test_features="--features mshv"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
grep focal sha1sums-x86_64 | sha1sum --check
|
||||
if [ $? -ne 0 ]; then
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
if ! grep focal sha1sums-x86_64 | sha1sum --check; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
# Download Cloud Hypervisor binary from its last stable release
|
||||
LAST_RELEASE_VERSION="v34.0"
|
||||
LAST_RELEASE_VERSION="v36.0"
|
||||
CH_RELEASE_URL="https://github.com/cloud-hypervisor/cloud-hypervisor/releases/download/$LAST_RELEASE_VERSION/cloud-hypervisor-static"
|
||||
CH_RELEASE_NAME="cloud-hypervisor-static"
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $CH_RELEASE_URL -O "$CH_RELEASE_NAME" || exit 1
|
||||
chmod +x $CH_RELEASE_NAME
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
@@ -60,15 +61,16 @@ fi
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
# Test ovs-dpdk relies on hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=$(grep Hugepagesize /proc/meminfo | awk '{print $2}')
|
||||
PAGE_NUM=$((12288 * 1024 / HUGEPAGESIZE))
|
||||
echo "$PAGE_NUM" | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
@@ -12,45 +14,45 @@ process_common_args "$@"
|
||||
# For now these values are default for kvm
|
||||
test_features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
if [ "$hypervisor" = "mshv" ]; then
|
||||
test_features="--features mshv"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
grep focal sha1sums-x86_64 | sha1sum --check
|
||||
if [ $? -ne 0 ]; then
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
if ! grep focal sha1sums-x86_64 | sha1sum --check; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
build_custom_linux
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test $test_features "rate_limiter::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
@@ -14,36 +16,32 @@ fi
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
pushd $WORKLOADS_DIR
|
||||
rm -f $FW
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
download_hypervisor_fw
|
||||
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
|
||||
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
|
||||
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $JAMMY_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.raw"
|
||||
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $JAMMY_OS_IMAGE_NAME $JAMMY_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
# This set of vfio tests require to be ran on a specific machine with
|
||||
@@ -7,25 +8,23 @@ set -x
|
||||
# out of the scope of this script, including the custom guest image with
|
||||
# Nvidia drivers installed, and properly configured Nvidia Tesla T4 card.
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
|
||||
# Always download the latest "hypervisor-fw"
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FW_URL -O hypervisor-fw || exit 1
|
||||
popd
|
||||
download_hypervisor_fw
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "vfio::test_nvidia" -- --test-threads=1 ${test_binary_args[*]}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
source $(dirname "$0")/common-aarch64.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
source "$(dirname "$0")"/common-aarch64.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
@@ -27,8 +29,8 @@ if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW} ]]; then
|
||||
fi
|
||||
|
||||
# Use device mapper to create a snapshot of the Windows image
|
||||
img_blk_size=$(du -b -B 512 ${WIN_IMAGE_FILE} | awk '{print $1;}')
|
||||
loop_device=$(losetup --find --show --read-only ${WIN_IMAGE_FILE})
|
||||
img_blk_size=$(du -b -B 512 "${WIN_IMAGE_FILE}" | awk '{print $1;}')
|
||||
loop_device=$(losetup --find --show --read-only "${WIN_IMAGE_FILE}")
|
||||
dmsetup create windows-base --table "0 $img_blk_size linear $loop_device 0"
|
||||
dmsetup mknodes
|
||||
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
|
||||
@@ -36,11 +38,11 @@ dmsetup mknodes
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
cargo build --all --release --target $BUILD_TARGET
|
||||
cargo build --all --release --target "$BUILD_TARGET"
|
||||
|
||||
# Only run with 1 thread to avoid tests interfering with one another because
|
||||
# Windows has a static IP configured
|
||||
time cargo test "windows::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
time cargo test "windows::$test_filter" --target "$BUILD_TARGET" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
dmsetup remove_all -f
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
# For now these values are default for kvm
|
||||
test_features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
if [ "$hypervisor" = "mshv" ]; then
|
||||
test_features="--features mshv"
|
||||
fi
|
||||
WIN_IMAGE_FILE="/root/workloads/windows-server-2022-amd64-2.raw"
|
||||
|
||||
WORKLOADS_DIR="/root/workloads"
|
||||
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||
if [ ! -f "$OVMF_FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $OVMF_FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
download_ovmf
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
@@ -41,7 +39,7 @@ dmsetup mknodes
|
||||
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
|
||||
dmsetup mknodes
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
@@ -12,103 +14,90 @@ process_common_args "$@"
|
||||
# For now these values are default for kvm
|
||||
test_features=""
|
||||
|
||||
if [ "$hypervisor" = "mshv" ] ; then
|
||||
if [ "$hypervisor" = "mshv" ]; then
|
||||
test_features="--features mshv"
|
||||
fi
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
cp scripts/sha1sums-x86_64 "$WORKLOADS_DIR"
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
if [ ! -f "$FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
download_hypervisor_fw
|
||||
|
||||
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||
if [ ! -f "$OVMF_FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $OVMF_FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
download_ovmf
|
||||
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0-backing.qcow2"
|
||||
FOCAL_OS_QCOW_BACKING_FILE_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_QCOW_BACKING_FILE_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img create -f qcow2 -b $FOCAL_OS_IMAGE -F qcow2 $FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img create -f qcow2 -b "$FOCAL_OS_IMAGE" -F qcow2 $FOCAL_OS_QCOW_BACKING_FILE_IMAGE_NAME
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
JAMMY_OS_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.qcow2"
|
||||
JAMMY_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$JAMMY_OS_IMAGE_NAME"
|
||||
JAMMY_OS_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $JAMMY_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
JAMMY_OS_RAW_IMAGE_NAME="jammy-server-cloudimg-amd64-custom-20230119-0.raw"
|
||||
JAMMY_OS_RAW_IMAGE="$WORKLOADS_DIR/$JAMMY_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$JAMMY_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $JAMMY_OS_IMAGE_NAME $JAMMY_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $ALPINE_MINIROOTFS_URL -O $ALPINE_MINIROOTFS_TARBALL || exit 1
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $ALPINE_MINIROOTFS_URL -O "$ALPINE_MINIROOTFS_TARBALL" || exit 1
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
ALPINE_INITRAMFS_IMAGE="$WORKLOADS_DIR/alpine_initramfs.img"
|
||||
if [ ! -f "$ALPINE_INITRAMFS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
mkdir alpine-minirootfs
|
||||
tar xf "$ALPINE_MINIROOTFS_TARBALL" -C alpine-minirootfs
|
||||
cat > alpine-minirootfs/init <<-EOF
|
||||
cat >alpine-minirootfs/init <<-EOF
|
||||
#! /bin/sh
|
||||
mount -t devtmpfs dev /dev
|
||||
echo \$TEST_STRING > /dev/console
|
||||
poweroff -f
|
||||
EOF
|
||||
chmod +x alpine-minirootfs/init
|
||||
cd alpine-minirootfs
|
||||
cd alpine-minirootfs || exit
|
||||
find . -print0 |
|
||||
cpio --null --create --verbose --owner root:root --format=newc > "$ALPINE_INITRAMFS_IMAGE"
|
||||
popd
|
||||
cpio --null --create --verbose --owner root:root --format=newc >"$ALPINE_INITRAMFS_IMAGE"
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
sha1sum sha1sums-x86_64 --check
|
||||
if [ $? -ne 0 ]; then
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
if ! sha1sum sha1sums-x86_64 --check; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
@@ -119,52 +108,51 @@ fi
|
||||
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||
VIRTIOFSD_DIR="virtiofsd_build"
|
||||
if [ ! -f "$VIRTIOFSD" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
git clone "https://gitlab.com/virtio-fs/virtiofsd.git" $VIRTIOFSD_DIR
|
||||
pushd $VIRTIOFSD_DIR
|
||||
git checkout v1.1.0
|
||||
pushd $VIRTIOFSD_DIR || exit
|
||||
git checkout v1.8.0
|
||||
time cargo build --release
|
||||
cp target/release/virtiofsd $VIRTIOFSD || exit 1
|
||||
popd
|
||||
cp target/release/virtiofsd "$VIRTIOFSD" || exit 1
|
||||
popd || exit
|
||||
rm -rf $VIRTIOFSD_DIR
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
|
||||
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
|
||||
MNT_DIR="mount_image"
|
||||
if [ ! -f "$BLK_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
fallocate -l 16M $BLK_IMAGE
|
||||
mkfs.ext4 -j $BLK_IMAGE
|
||||
mkdir $MNT_DIR
|
||||
sudo mount -t ext4 $BLK_IMAGE $MNT_DIR
|
||||
sudo bash -c "echo bar > $MNT_DIR/foo" || exit 1
|
||||
sudo umount $BLK_IMAGE
|
||||
rm -r $MNT_DIR
|
||||
popd
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
fallocate -l 16M "$BLK_IMAGE"
|
||||
mkfs.ext4 -j "$BLK_IMAGE"
|
||||
mkdir $MNT_DIR
|
||||
sudo mount -t ext4 "$BLK_IMAGE" $MNT_DIR
|
||||
sudo bash -c "echo bar > $MNT_DIR/foo" || exit 1
|
||||
sudo umount "$BLK_IMAGE"
|
||||
rm -r $MNT_DIR
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
SHARED_DIR="$WORKLOADS_DIR/shared_dir"
|
||||
if [ ! -d "$SHARED_DIR" ]; then
|
||||
mkdir -p $SHARED_DIR
|
||||
echo "foo" > "$SHARED_DIR/file1"
|
||||
echo "bar" > "$SHARED_DIR/file3" || exit 1
|
||||
mkdir -p "$SHARED_DIR"
|
||||
echo "foo" >"$SHARED_DIR/file1"
|
||||
echo "bar" >"$SHARED_DIR/file3" || exit 1
|
||||
fi
|
||||
|
||||
VFIO_DIR="$WORKLOADS_DIR/vfio"
|
||||
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
|
||||
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
|
||||
mkdir -p $VFIO_DIR
|
||||
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
rm -rf "$VFIO_DIR" "$VFIO_DISK_IMAGE"
|
||||
mkdir -p "$VFIO_DIR"
|
||||
cp "$FOCAL_OS_RAW_IMAGE" "$VFIO_DIR"
|
||||
cp "$FW" "$VFIO_DIR"
|
||||
cp "$VMLINUX_IMAGE" "$VFIO_DIR" || exit 1
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
# We always copy a fresh version of our binary for our L2 guest.
|
||||
cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
|
||||
cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR
|
||||
cp target/"$BUILD_TARGET"/release/cloud-hypervisor "$VFIO_DIR"
|
||||
cp target/"$BUILD_TARGET"/release/ch-remote "$VFIO_DIR"
|
||||
|
||||
# Enable KSM with some reasonable parameters so that it won't take too long
|
||||
# for the memory to be merged between two processes.
|
||||
@@ -173,9 +161,9 @@ 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
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=$(grep Hugepagesize /proc/meminfo | awk '{print $2}')
|
||||
PAGE_NUM=$((12288 * 1024 / HUGEPAGESIZE))
|
||||
echo "$PAGE_NUM" | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Update max locked memory to 'unlimited' to avoid issues with vDPA
|
||||
@@ -198,7 +186,7 @@ fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --features "mshv,dbus_api" --all --release --target $BUILD_TARGET
|
||||
cargo build --features "mshv,dbus_api" --all --release --target "$BUILD_TARGET"
|
||||
export RUST_BACKTRACE=1
|
||||
# integration tests now do not reply on build feature "dbus_api"
|
||||
time cargo test $test_features "dbus_api::$test_filter" -- ${test_binary_args[*]}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -x
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
export TEST_ARCH=$(uname -m)
|
||||
TEST_ARCH=$(uname -m)
|
||||
export TEST_ARCH
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
@@ -15,34 +17,34 @@ build_fio() {
|
||||
|
||||
checkout_repo "$FIO_DIR" "$FIO_REPO" master "1953e1adb5a28ed21370e85991d7f5c3cdc699f3"
|
||||
if [ ! -f "$FIO_DIR/.built" ]; then
|
||||
pushd $FIO_DIR
|
||||
pushd "$FIO_DIR" || exit
|
||||
./configure
|
||||
make -j `nproc`
|
||||
make -j "$(nproc)"
|
||||
cp fio "$WORKLOADS_DIR/fio"
|
||||
touch .built
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
}
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
cp scripts/sha1sums-${TEST_ARCH} $WORKLOADS_DIR
|
||||
cp scripts/sha1sums-"${TEST_ARCH}" "$WORKLOADS_DIR"
|
||||
|
||||
if [ ${TEST_ARCH} == "aarch64" ]; then
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-arm64-custom-20210929-0.qcow2"
|
||||
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"
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
fi
|
||||
|
||||
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
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
if [ ${TEST_ARCH} == "aarch64" ]; then
|
||||
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"
|
||||
@@ -50,20 +52,19 @@ fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
grep focal sha1sums-${TEST_ARCH} | sha1sum --check
|
||||
if [ $? -ne 0 ]; then
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
if ! grep focal sha1sums-"${TEST_ARCH}" | sha1sum --check; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
popd || exit
|
||||
|
||||
if [ ${TEST_ARCH} == "aarch64" ]; then
|
||||
if [ "${TEST_ARCH}" == "aarch64" ]; then
|
||||
build_fio
|
||||
|
||||
# Update the fio in the cloud image to use io_uring on AArch64
|
||||
@@ -84,15 +85,16 @@ build_custom_linux
|
||||
|
||||
CFLAGS=""
|
||||
if [[ "${BUILD_TARGET}" == "${TEST_ARCH}-unknown-linux-musl" ]]; then
|
||||
# shellcheck disable=SC2034
|
||||
CFLAGS="-I /usr/include/${TEST_ARCH}-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --features mshv --all --release --target $BUILD_TARGET
|
||||
cargo build --features mshv --all --release --target "$BUILD_TARGET"
|
||||
|
||||
# setup hugepages
|
||||
HUGEPAGESIZE=`grep Hugepagesize /proc/meminfo | awk '{print $2}'`
|
||||
PAGE_NUM=`echo $((12288 * 1024 / $HUGEPAGESIZE))`
|
||||
echo $PAGE_NUM | sudo tee /proc/sys/vm/nr_hugepages
|
||||
HUGEPAGESIZE=$(grep Hugepagesize /proc/meminfo | awk '{print $2}')
|
||||
PAGE_NUM=$((12288 * 1024 / HUGEPAGESIZE))
|
||||
echo "$PAGE_NUM" | sudo tee /proc/sys/vm/nr_hugepages
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
if [ -n "$test_filter" ]; then
|
||||
@@ -100,15 +102,16 @@ if [ -n "$test_filter" ]; then
|
||||
fi
|
||||
|
||||
# Ensure that git commands can be run in this directory (for metrics report)
|
||||
git config --global --add safe.directory $PWD
|
||||
git config --global --add safe.directory "$PWD"
|
||||
|
||||
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE`
|
||||
if [ -z $RUST_BACKTRACE_VALUE ];then
|
||||
export RUST_BACKTRACE=1
|
||||
RUST_BACKTRACE_VALUE=$RUST_BACKTRACE
|
||||
if [ -z "$RUST_BACKTRACE_VALUE" ]; then
|
||||
export RUST_BACKTRACE=1
|
||||
else
|
||||
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
|
||||
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
|
||||
fi
|
||||
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||
# shellcheck disable=SC2048,SC2086
|
||||
time target/"$BUILD_TARGET"/release/performance-metrics ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
set -x
|
||||
|
||||
sudo docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli validate -i /local/vmm/src/api/openapi/cloud-hypervisor.yaml
|
||||
sudo docker run --rm -v "${PWD}":/local openapitools/openapi-generator-cli validate -i /local/vmm/src/api/openapi/cloud-hypervisor.yaml
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2068
|
||||
|
||||
source $HOME/.cargo/env
|
||||
source $(dirname "$0")/test-util.sh
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME"/.cargo/env
|
||||
source "$(dirname "$0")"/test-util.sh
|
||||
|
||||
process_common_args "$@"
|
||||
|
||||
cargo_args=("")
|
||||
|
||||
# shellcheck disable=SC2154
|
||||
if [[ $hypervisor = "mshv" ]]; then
|
||||
cargo_args+=("--features $hypervisor")
|
||||
elif [[ $(uname -m) = "x86_64" ]]; then
|
||||
@@ -14,5 +17,5 @@ elif [[ $(uname -m) = "x86_64" ]]; then
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
|
||||
cargo test --doc --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1
|
||||
cargo test --lib --bins --target "$BUILD_TARGET" --workspace ${cargo_args[@]} || exit 1
|
||||
cargo test --doc --target "$BUILD_TARGET" --workspace ${cargo_args[@]} || exit 1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
hypervisor="kvm"
|
||||
test_filter=""
|
||||
|
||||
@@ -18,13 +18,13 @@ checkout_repo() {
|
||||
# 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
|
||||
pushd "$SRC_DIR" || exit
|
||||
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
|
||||
popd || exit
|
||||
if [ "$SRC_LOCAL_COMMIT" != "$GIT_COMMIT" ]; then
|
||||
rm -rf "$SRC_DIR"
|
||||
fi
|
||||
@@ -34,10 +34,10 @@ checkout_repo() {
|
||||
if [ ! -d "$SRC_DIR" ]; then
|
||||
git clone --depth 1 "$GIT_URL" -b "$GIT_BRANCH" "$SRC_DIR"
|
||||
if [ "$GIT_COMMIT" ]; then
|
||||
pushd "$SRC_DIR"
|
||||
pushd "$SRC_DIR" || exit
|
||||
git fetch --depth 1 origin "$GIT_COMMIT"
|
||||
git reset --hard FETCH_HEAD
|
||||
popd
|
||||
popd || exit
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -51,23 +51,23 @@ build_custom_linux() {
|
||||
|
||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||
|
||||
cp $SRCDIR/resources/linux-config-${ARCH} $LINUX_CUSTOM_DIR/.config
|
||||
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
|
||||
pushd "$LINUX_CUSTOM_DIR" || exit
|
||||
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
|
||||
popd || exit
|
||||
}
|
||||
|
||||
cmd_help() {
|
||||
echo ""
|
||||
echo "Cloud Hypervisor $(basename $0)"
|
||||
echo "Usage: $(basename $0) [<args>]"
|
||||
echo "Cloud Hypervisor $(basename "$0")"
|
||||
echo "Usage: $(basename "$0") [<args>]"
|
||||
echo ""
|
||||
echo "Available arguments:"
|
||||
echo ""
|
||||
@@ -80,30 +80,61 @@ cmd_help() {
|
||||
|
||||
process_common_args() {
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
||||
"--hypervisor")
|
||||
shift
|
||||
hypervisor="$1"
|
||||
;;
|
||||
"--test-filter")
|
||||
shift
|
||||
test_filter="$1"
|
||||
;;
|
||||
"--") {
|
||||
shift
|
||||
break
|
||||
} ;;
|
||||
*)
|
||||
echo "Unknown test scripts argument: $1. Please use '-- --help' for help."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
case "$1" in
|
||||
"-h" | "--help") {
|
||||
cmd_help
|
||||
exit 1
|
||||
} ;;
|
||||
"--hypervisor")
|
||||
shift
|
||||
hypervisor="$1"
|
||||
;;
|
||||
"--test-filter")
|
||||
shift
|
||||
# shellcheck disable=SC2034
|
||||
test_filter="$1"
|
||||
;;
|
||||
"--") {
|
||||
shift
|
||||
break
|
||||
} ;;
|
||||
*)
|
||||
echo "Unknown test scripts argument: $1. Please use '-- --help' for help."
|
||||
exit
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||
die "Hypervisor value must be kvm or mshv"
|
||||
fi
|
||||
|
||||
test_binary_args=($@)
|
||||
# shellcheck disable=SC2034
|
||||
test_binary_args=("$@")
|
||||
}
|
||||
|
||||
download_hypervisor_fw() {
|
||||
if [ -n "$AUTH_DOWNLOAD_TOKEN" ]; then
|
||||
echo "Using authenticated download from GitHub"
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest \
|
||||
--header "Authorization: Token $AUTH_DOWNLOAD_TOKEN" \
|
||||
--header "X-GitHub-Api-Version: 2022-11-28" | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
else
|
||||
echo "Using anonymous download from GitHub"
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
fi
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
rm -f "$FW"
|
||||
time wget --quiet "$FW_URL" || exit 1
|
||||
popd || exit
|
||||
}
|
||||
|
||||
download_ovmf() {
|
||||
OVMF_FW_TAG="ch-6624aa331f"
|
||||
OVMF_FW_URL="https://github.com/cloud-hypervisor/edk2/releases/download/$OVMF_FW_TAG/CLOUDHV.fd"
|
||||
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||
pushd "$WORKLOADS_DIR" || exit
|
||||
rm -f "$OVMF_FW"
|
||||
time wget --quiet $OVMF_FW_URL || exit 1
|
||||
popd || exit
|
||||
}
|
||||
|
||||
123
src/main.rs
123
src/main.rs
@@ -20,6 +20,7 @@ use std::sync::{Arc, Mutex};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
|
||||
use vmm::api::ApiAction;
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
@@ -240,6 +241,13 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("rate-limit-group")
|
||||
.long("rate-limit-group")
|
||||
.help(config::RateLimiterGroupConfig::SYNTAX)
|
||||
.num_args(1..)
|
||||
.group("vm-config"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("disk")
|
||||
.long("disk")
|
||||
@@ -410,6 +418,15 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
|
||||
.group("vm-config"),
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let app = app.arg(
|
||||
Arg::new("debug-console")
|
||||
.long("debug-console")
|
||||
.help("Debug console: off|pty|tty|file=</path/to/a/file>,iobase=<port in hex>")
|
||||
.default_value("off,iobase=0xe9")
|
||||
.group("vm-config"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let app = app.arg(
|
||||
Arg::new("gdb")
|
||||
@@ -443,7 +460,14 @@ fn create_app(default_vcpus: String, default_memory: String, default_rng: String
|
||||
.num_args(0)
|
||||
.group("vmm-config"),
|
||||
);
|
||||
|
||||
#[cfg(feature = "igvm")]
|
||||
let app = app.arg(
|
||||
Arg::new("igvm")
|
||||
.long("igvm")
|
||||
.help("Path to IGVM file to load.")
|
||||
.num_args(1)
|
||||
.group("vm-config"),
|
||||
);
|
||||
app.arg(
|
||||
Arg::new("version")
|
||||
.short('V')
|
||||
@@ -598,6 +622,7 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(true)
|
||||
.open(parser.get("path").unwrap())
|
||||
.map_err(Error::EventMonitorIo)?,
|
||||
))
|
||||
@@ -672,6 +697,11 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
.map_err(Error::StartVmmThread)?;
|
||||
|
||||
let r: Result<(), Error> = (|| {
|
||||
#[cfg(feature = "igvm")]
|
||||
let payload_present = cmd_arguments.contains_id("kernel")
|
||||
|| cmd_arguments.contains_id("firmware")
|
||||
|| cmd_arguments.contains_id("igvm");
|
||||
#[cfg(not(feature = "igvm"))]
|
||||
let payload_present =
|
||||
cmd_arguments.contains_id("kernel") || cmd_arguments.contains_id("firmware");
|
||||
|
||||
@@ -681,22 +711,24 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
||||
|
||||
// Create and boot the VM based off the VM config we just built.
|
||||
let sender = api_request_sender.clone();
|
||||
vmm::api::vm_create(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(Mutex::new(vm_config)),
|
||||
)
|
||||
.map_err(Error::VmCreate)?;
|
||||
vmm::api::vm_boot(api_evt.try_clone().unwrap(), sender).map_err(Error::VmBoot)?;
|
||||
vmm::api::VmCreate
|
||||
.send(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(Mutex::new(vm_config)),
|
||||
)
|
||||
.map_err(Error::VmCreate)?;
|
||||
vmm::api::VmBoot
|
||||
.send(api_evt.try_clone().unwrap(), sender, ())
|
||||
.map_err(Error::VmBoot)?;
|
||||
} else if let Some(restore_params) = cmd_arguments.get_one::<String>("restore") {
|
||||
vmm::api::vm_restore(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(
|
||||
vmm::api::VmRestore
|
||||
.send(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
config::RestoreConfig::parse(restore_params).map_err(Error::ParsingRestore)?,
|
||||
),
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -726,6 +758,9 @@ fn main() {
|
||||
#[cfg(all(feature = "tdx", feature = "sev_snp"))]
|
||||
compile_error!("Feature 'tdx' and 'sev_snp' are mutually exclusive.");
|
||||
|
||||
#[cfg(all(feature = "sev_snp", not(target_arch = "x86_64")))]
|
||||
compile_error!("Feature 'sev_snp' needs target 'x86_64'");
|
||||
|
||||
#[cfg(feature = "dhat-heap")]
|
||||
let _profiler = dhat::Profiler::new_heap();
|
||||
|
||||
@@ -772,6 +807,8 @@ mod unit_tests {
|
||||
ConsoleConfig, ConsoleOutputMode, CpuFeatures, CpusConfig, MemoryConfig, PayloadConfig,
|
||||
RngConfig, VmConfig, VmParams,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vmm::vm_config::DebugConsoleConfig;
|
||||
|
||||
fn get_vm_config_from_vec(args: &[&str]) -> VmConfig {
|
||||
let (default_vcpus, default_memory, default_rng) = prepare_default_values();
|
||||
@@ -833,8 +870,13 @@ mod unit_tests {
|
||||
},
|
||||
payload: Some(PayloadConfig {
|
||||
kernel: Some(PathBuf::from("/path/to/kernel")),
|
||||
..Default::default()
|
||||
firmware: None,
|
||||
cmdline: None,
|
||||
initramfs: None,
|
||||
#[cfg(feature = "igvm")]
|
||||
igvm: None,
|
||||
}),
|
||||
rate_limit_groups: None,
|
||||
disks: None,
|
||||
net: None,
|
||||
rng: RngConfig {
|
||||
@@ -856,6 +898,8 @@ mod unit_tests {
|
||||
iommu: false,
|
||||
socket: None,
|
||||
},
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
debug_console: DebugConsoleConfig::default(),
|
||||
devices: None,
|
||||
user_devices: None,
|
||||
vdpa: None,
|
||||
@@ -1106,6 +1150,29 @@ mod unit_tests {
|
||||
}"#,
|
||||
true,
|
||||
),
|
||||
(
|
||||
vec![
|
||||
"cloud-hypervisor",
|
||||
"--kernel",
|
||||
"/path/to/kernel",
|
||||
"--disk",
|
||||
"path=/path/to/disk/1,rate_limit_group=group0",
|
||||
"path=/path/to/disk/2,rate_limit_group=group0",
|
||||
"--rate-limit-group",
|
||||
"id=group0,bw_size=1000,bw_refill_time=100",
|
||||
],
|
||||
r#"{
|
||||
"payload": {"kernel": "/path/to/kernel"},
|
||||
"disks": [
|
||||
{"path": "/path/to/disk/1", "rate_limit_group": "group0"},
|
||||
{"path": "/path/to/disk/2", "rate_limit_group": "group0"}
|
||||
],
|
||||
"rate_limit_groups": [
|
||||
{"id": "group0", "rate_limiter_config": {"bandwidth": {"size": 1000, "one_time_burst": 0, "refill_time": 100}}}
|
||||
]
|
||||
}"#,
|
||||
true,
|
||||
),
|
||||
]
|
||||
.iter()
|
||||
.for_each(|(cli, openapi, equal)| {
|
||||
@@ -1464,6 +1531,30 @@ mod unit_tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[test]
|
||||
fn test_valid_vm_config_debug_console() {
|
||||
[(
|
||||
vec![
|
||||
"cloud-hypervisor",
|
||||
"--kernel",
|
||||
"/path/to/kernel",
|
||||
"--debug-console",
|
||||
"tty,iobase=0xe9",
|
||||
],
|
||||
// 233 == 0xe9
|
||||
r#"{
|
||||
"payload": {"kernel": "/path/to/kernel" },
|
||||
"debug_console": {"mode": "Tty", "iobase": 233 }
|
||||
}"#,
|
||||
true,
|
||||
)]
|
||||
.iter()
|
||||
.for_each(|(cli, openapi, equal)| {
|
||||
compare_vm_config_cli_vs_json(cli, openapi, *equal);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_valid_vm_config_serial_console() {
|
||||
[
|
||||
|
||||
@@ -7,10 +7,10 @@ edition = "2021"
|
||||
[dependencies]
|
||||
dirs = "5.0.0"
|
||||
epoll = "4.3.3"
|
||||
libc = "0.2.147"
|
||||
once_cell = "1.18.0"
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.107"
|
||||
libc = "0.2.153"
|
||||
once_cell = "1.19.0"
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.109"
|
||||
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -90,7 +90,7 @@ impl GuestNetworkConfig {
|
||||
None => DEFAULT_TCP_LISTENER_TIMEOUT,
|
||||
};
|
||||
|
||||
match (|| -> Result<(), WaitForBootError> {
|
||||
let mut closure = || -> Result<(), WaitForBootError> {
|
||||
let listener =
|
||||
TcpListener::bind(listen_addr.as_str()).map_err(WaitForBootError::Listen)?;
|
||||
listener
|
||||
@@ -143,17 +143,19 @@ impl GuestNetworkConfig {
|
||||
Err(WaitForBootError::Accept(e))
|
||||
}
|
||||
}
|
||||
})() {
|
||||
};
|
||||
|
||||
match closure() {
|
||||
Err(e) => {
|
||||
let duration = start.elapsed();
|
||||
eprintln!(
|
||||
"\n\n==== Start 'wait_vm_boot' (FAILED) ====\n\n\
|
||||
duration =\"{duration:?}, timeout = {timeout}s\"\n\
|
||||
listen_addr=\"{listen_addr}\"\n\
|
||||
expected_guest_addr=\"{expected_guest_addr}\"\n\
|
||||
message=\"{s}\"\n\
|
||||
error=\"{e:?}\"\n\
|
||||
\n==== End 'wait_vm_boot' outout ====\n\n"
|
||||
"\n\n==== Start 'wait_vm_boot' (FAILED) ==== \
|
||||
\n\nduration =\"{duration:?}, timeout = {timeout}s\" \
|
||||
\nlisten_addr=\"{listen_addr}\" \
|
||||
\nexpected_guest_addr=\"{expected_guest_addr}\" \
|
||||
\nmessage=\"{s}\" \
|
||||
\nerror=\"{e:?}\" \
|
||||
\n\n==== End 'wait_vm_boot' outout ====\n\n"
|
||||
);
|
||||
|
||||
Err(e)
|
||||
@@ -559,7 +561,7 @@ fn scp_to_guest_with_auth(
|
||||
) -> Result<(), SshCommandError> {
|
||||
let mut counter = 0;
|
||||
loop {
|
||||
match (|| -> Result<(), SshCommandError> {
|
||||
let closure = || -> Result<(), SshCommandError> {
|
||||
let tcp =
|
||||
TcpStream::connect(format!("{ip}:22")).map_err(SshCommandError::Connection)?;
|
||||
let mut sess = Session::new().unwrap();
|
||||
@@ -592,7 +594,9 @@ fn scp_to_guest_with_auth(
|
||||
let _ = channel.wait_close();
|
||||
|
||||
Ok(())
|
||||
})() {
|
||||
};
|
||||
|
||||
match closure() {
|
||||
Ok(_) => break,
|
||||
Err(e) => {
|
||||
counter += 1;
|
||||
@@ -647,7 +651,7 @@ pub fn ssh_command_ip_with_auth(
|
||||
|
||||
let mut counter = 0;
|
||||
loop {
|
||||
match (|| -> Result<(), SshCommandError> {
|
||||
let mut closure = || -> Result<(), SshCommandError> {
|
||||
let tcp =
|
||||
TcpStream::connect(format!("{ip}:22")).map_err(SshCommandError::Connection)?;
|
||||
let mut sess = Session::new().unwrap();
|
||||
@@ -676,7 +680,9 @@ pub fn ssh_command_ip_with_auth(
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
})() {
|
||||
};
|
||||
|
||||
match closure() {
|
||||
Ok(_) => break,
|
||||
Err(e) => {
|
||||
counter += 1;
|
||||
@@ -718,18 +724,77 @@ pub fn ssh_command_ip(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn exec_host_command_with_retries(command: &str, retries: u32, interval: Duration) -> bool {
|
||||
for _ in 0..retries {
|
||||
let s = exec_host_command_output(command).status;
|
||||
if !s.success() {
|
||||
eprintln!("\n\n==== retrying in {:?} ===\n\n", interval);
|
||||
thread::sleep(interval);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn exec_host_command_status(command: &str) -> ExitStatus {
|
||||
std::process::Command::new("bash")
|
||||
.args(["-c", command])
|
||||
.status()
|
||||
.unwrap_or_else(|_| panic!("Expected '{command}' to run"))
|
||||
exec_host_command_output(command).status
|
||||
}
|
||||
|
||||
pub fn exec_host_command_output(command: &str) -> Output {
|
||||
std::process::Command::new("bash")
|
||||
let output = std::process::Command::new("bash")
|
||||
.args(["-c", command])
|
||||
.output()
|
||||
.unwrap_or_else(|_| panic!("Expected '{command}' to run"))
|
||||
.unwrap_or_else(|e| panic!("Expected '{command}' to run. Error: {:?}", e));
|
||||
|
||||
if !output.status.success() {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
eprintln!(
|
||||
"\n\n==== Start 'exec_host_command' failed ==== \
|
||||
\n\n---stdout---\n{stdout}\n---stderr---{stderr} \
|
||||
\n\n==== End 'exec_host_command' failed ====",
|
||||
);
|
||||
}
|
||||
|
||||
output
|
||||
}
|
||||
|
||||
pub fn check_lines_count(input: &str, line_count: usize) -> bool {
|
||||
if input.lines().count() == line_count {
|
||||
true
|
||||
} else {
|
||||
eprintln!(
|
||||
"\n\n==== Start 'check_lines_count' failed ==== \
|
||||
\n\ninput = {input}\nline_count = {line_count} \
|
||||
\n\n==== End 'check_lines_count' failed ====",
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_matched_lines_count(input: &str, keywords: Vec<&str>, line_count: usize) -> bool {
|
||||
let mut matches = String::new();
|
||||
for line in input.lines() {
|
||||
if keywords.iter().all(|k| line.contains(k)) {
|
||||
matches += line;
|
||||
}
|
||||
}
|
||||
|
||||
if matches.lines().count() == line_count {
|
||||
true
|
||||
} else {
|
||||
eprintln!(
|
||||
"\n\n==== Start 'check_matched_lines_count' failed ==== \
|
||||
\nkeywords = {keywords:?}, line_count = {line_count} \
|
||||
\n\ninput = {input} matches = {matches} \
|
||||
\n\n==== End 'check_matched_lines_count' failed ====",
|
||||
);
|
||||
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub const PIPE_SIZE: i32 = 32 << 20;
|
||||
@@ -1337,7 +1402,7 @@ pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Resu
|
||||
})
|
||||
.map_err(|_| {
|
||||
eprintln!(
|
||||
"=============== iperf3 output ===============\n\n{}\n\n===========end============\n\n",
|
||||
"==== Start iperf3 output ===\n\n{}\n\n=== End iperf3 output ===\n\n",
|
||||
String::from_utf8_lossy(output)
|
||||
);
|
||||
Error::Iperf3Parse
|
||||
@@ -1415,9 +1480,7 @@ pub fn parse_fio_output(output: &str, fio_ops: &FioOps, num_jobs: u32) -> Result
|
||||
total_bps
|
||||
})
|
||||
.map_err(|_| {
|
||||
eprintln!(
|
||||
"=============== Fio output ===============\n\n{output}\n\n===========end============\n\n"
|
||||
);
|
||||
eprintln!("=== Start Fio output ===\n\n{output}\n\n=== End Fio output ===\n\n");
|
||||
Error::FioOutputParse
|
||||
})
|
||||
}
|
||||
@@ -1470,9 +1533,7 @@ pub fn parse_fio_output_iops(output: &str, fio_ops: &FioOps, num_jobs: u32) -> R
|
||||
total_iops
|
||||
})
|
||||
.map_err(|_| {
|
||||
eprintln!(
|
||||
"=============== Fio output ===============\n\n{output}\n\n===========end============\n\n"
|
||||
);
|
||||
eprintln!("=== Start Fio output ===\n\n{output}\n\n=== End Fio output ===\n\n");
|
||||
Error::FioOutputParse
|
||||
})
|
||||
}
|
||||
@@ -1605,7 +1666,7 @@ pub fn parse_ethr_latency_output(output: &[u8]) -> Result<Vec<f64>, Error> {
|
||||
})
|
||||
.map_err(|_| {
|
||||
eprintln!(
|
||||
"=============== ethr output ===============\n\n{}\n\n===========end============\n\n",
|
||||
"=== Start ethr output ===\n\n{}\n\n=== End ethr output ===\n\n",
|
||||
String::from_utf8_lossy(output)
|
||||
);
|
||||
Error::EthrLogParse
|
||||
|
||||
@@ -687,6 +687,8 @@ fn resize_command(
|
||||
device_id: None,
|
||||
},
|
||||
];
|
||||
// See: #5938
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
assert!(check_latest_events_exact(&latest_events, event_path));
|
||||
}
|
||||
|
||||
@@ -858,6 +860,7 @@ fn fw_path(_fw_type: FwType) -> String {
|
||||
fw_path.to_str().unwrap().to_string()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MetaEvent {
|
||||
event: String,
|
||||
device_id: Option<String>,
|
||||
@@ -910,7 +913,18 @@ fn check_sequential_events(expected_events: &[&MetaEvent], event_file: &str) ->
|
||||
}
|
||||
}
|
||||
|
||||
idx == len
|
||||
let ret = idx == len;
|
||||
|
||||
if !ret {
|
||||
eprintln!(
|
||||
"\n\n==== Start 'check_sequential_events' failed ==== \
|
||||
\n\nexpected_events={:?}\nactual_events={:?} \
|
||||
\n\n==== End 'check_sequential_events' failed ====",
|
||||
expected_events, json_events,
|
||||
);
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
// Return true if all events from the input 'expected_events' are matched exactly
|
||||
@@ -922,6 +936,13 @@ fn check_sequential_events_exact(expected_events: &[&MetaEvent], event_file: &st
|
||||
|
||||
for (idx, e) in json_events.iter().enumerate() {
|
||||
if !expected_events[idx].match_with_json_event(e) {
|
||||
eprintln!(
|
||||
"\n\n==== Start 'check_sequential_events_exact' failed ==== \
|
||||
\n\nexpected_events={:?}\nactual_events={:?} \
|
||||
\n\n==== End 'check_sequential_events_exact' failed ====",
|
||||
expected_events, json_events,
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -938,6 +959,13 @@ fn check_latest_events_exact(latest_events: &[&MetaEvent], event_file: &str) ->
|
||||
|
||||
for (idx, e) in json_events.iter().enumerate() {
|
||||
if !latest_events[idx].match_with_json_event(e) {
|
||||
eprintln!(
|
||||
"\n\n==== Start 'check_latest_events_exact' failed ==== \
|
||||
\n\nexpected_events={:?}\nactual_events={:?} \
|
||||
\n\n==== End 'check_latest_events_exact' failed ====",
|
||||
latest_events, json_events,
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1007,6 +1035,40 @@ fn test_cpu_topology(threads_per_core: u8, cores_per_package: u8, packages: u8,
|
||||
.unwrap_or(0),
|
||||
packages
|
||||
);
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
let mut cpu_id = 0;
|
||||
for package_id in 0..packages {
|
||||
for core_id in 0..cores_per_package {
|
||||
for _ in 0..threads_per_core {
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command(&format!("cat /sys/devices/system/cpu/cpu{cpu_id}/topology/physical_package_id"))
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u8>()
|
||||
.unwrap_or(0),
|
||||
package_id
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command(&format!(
|
||||
"cat /sys/devices/system/cpu/cpu{cpu_id}/topology/core_id"
|
||||
))
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u8>()
|
||||
.unwrap_or(0),
|
||||
core_id
|
||||
);
|
||||
|
||||
cpu_id += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
@@ -2057,7 +2119,7 @@ fn pty_read(mut pty: std::fs::File) -> Receiver<String> {
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
let mut buf = [0; 512];
|
||||
match pty.read(&mut buf) {
|
||||
Ok(_) => {
|
||||
Ok(_bytes) => {
|
||||
let output = std::str::from_utf8(&buf).unwrap().to_string();
|
||||
match tx.send(output) {
|
||||
Ok(_) => (),
|
||||
@@ -2513,7 +2575,63 @@ mod common_parallel {
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_virtio_queue_affinity() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
// We need the host to have at least 4 CPUs if we want to be able
|
||||
// to run this test.
|
||||
let host_cpus_count = exec_host_command_output("nproc");
|
||||
assert!(
|
||||
String::from_utf8_lossy(&host_cpus_count.stdout)
|
||||
.trim()
|
||||
.parse::<u16>()
|
||||
.unwrap_or(0)
|
||||
>= 4
|
||||
);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", "boot=4"])
|
||||
.args(["--memory", "size=512M"])
|
||||
.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={},num_queues=4,queue_affinity=[0@[0,2],1@[1,3],2@[1],3@[3]]",
|
||||
guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||
)
|
||||
.as_str(),
|
||||
])
|
||||
.default_net()
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
let pid = child.id();
|
||||
let taskset_q0 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q0 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str());
|
||||
assert_eq!(String::from_utf8_lossy(&taskset_q0.stdout).trim(), "0,2");
|
||||
let taskset_q1 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q1 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str());
|
||||
assert_eq!(String::from_utf8_lossy(&taskset_q1.stdout).trim(), "1,3");
|
||||
let taskset_q2 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q2 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str());
|
||||
assert_eq!(String::from_utf8_lossy(&taskset_q2.stdout).trim(), "1");
|
||||
let taskset_q3 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q3 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str());
|
||||
assert_eq!(String::from_utf8_lossy(&taskset_q3.stdout).trim(), "3");
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
@@ -3405,16 +3523,19 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fn test_vhost_user_blk_default() {
|
||||
test_vhost_user_blk(2, false, false, Some(&prepare_vubd))
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fn test_vhost_user_blk_readonly() {
|
||||
test_vhost_user_blk(1, true, false, Some(&prepare_vubd))
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fn test_vhost_user_blk_direct() {
|
||||
test_vhost_user_blk(1, false, true, Some(&prepare_vubd))
|
||||
}
|
||||
@@ -3929,7 +4050,7 @@ mod common_parallel {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
let serial_path = guest.tmp_dir.as_path().join("/tmp/serial-output");
|
||||
let serial_path = guest.tmp_dir.as_path().join("serial-output");
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let console_str: &str = "console=ttyS0";
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -4042,8 +4163,8 @@ mod common_parallel {
|
||||
fn test_serial_socket_interaction() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
let serial_socket = guest.tmp_dir.as_path().join("/tmp/serial.socket");
|
||||
let serial_socket_pty = guest.tmp_dir.as_path().join("/tmp/serial.pty");
|
||||
let serial_socket = guest.tmp_dir.as_path().join("serial.socket");
|
||||
let serial_socket_pty = guest.tmp_dir.as_path().join("serial.pty");
|
||||
let serial_option = if cfg!(target_arch = "x86_64") {
|
||||
" console=ttyS0"
|
||||
} else {
|
||||
@@ -4097,7 +4218,12 @@ mod common_parallel {
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the cloud-hypervisor binary actually terminated
|
||||
assert!(output.status.success())
|
||||
if !output.status.success() {
|
||||
panic!(
|
||||
"Cloud Hypervisor process failed to terminate gracefully: {:?}",
|
||||
output.status
|
||||
);
|
||||
}
|
||||
});
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
@@ -4151,7 +4277,7 @@ mod common_parallel {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
let console_path = guest.tmp_dir.as_path().join("/tmp/console-output");
|
||||
let console_path = guest.tmp_dir.as_path().join("console-output");
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", "boot=1"])
|
||||
.args(["--memory", "size=512M"])
|
||||
@@ -4212,8 +4338,8 @@ mod common_parallel {
|
||||
fn test_vfio() {
|
||||
setup_vfio_network_interfaces();
|
||||
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new_from_ip_range(Box::new(focal), "172.18", 0);
|
||||
let jammy = UbuntuDiskConfig::new(JAMMY_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new_from_ip_range(Box::new(jammy), "172.18", 0);
|
||||
|
||||
let mut workload_path = dirs::home_dir().unwrap();
|
||||
workload_path.push("workloads");
|
||||
@@ -4318,49 +4444,35 @@ mod common_parallel {
|
||||
// Let's ssh into it and verify that it's there. If it is it means
|
||||
// we're in the right guest (The L2 one) because the QEMU L1 guest
|
||||
// does not have this command line tag.
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command_l2_1("grep -c VFIOTAG /proc/cmdline")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
assert!(check_matched_lines_count(
|
||||
guest.ssh_command_l2_1("cat /proc/cmdline").unwrap().trim(),
|
||||
vec!["VFIOTAG"],
|
||||
1
|
||||
);
|
||||
));
|
||||
|
||||
// Let's also verify from the second virtio-net device passed to
|
||||
// the L2 VM.
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command_l2_2("grep -c VFIOTAG /proc/cmdline")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
assert!(check_matched_lines_count(
|
||||
guest.ssh_command_l2_2("cat /proc/cmdline").unwrap().trim(),
|
||||
vec!["VFIOTAG"],
|
||||
1
|
||||
);
|
||||
));
|
||||
|
||||
// Check the amount of PCI devices appearing in L2 VM.
|
||||
assert_eq!(
|
||||
assert!(check_lines_count(
|
||||
guest
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices | wc -l")
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
8,
|
||||
);
|
||||
.trim(),
|
||||
8
|
||||
));
|
||||
|
||||
// Check both if /dev/vdc exists and if the block size is 16M in L2 VM
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command_l2_1("lsblk | grep vdc | grep -c 16M")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
assert!(check_matched_lines_count(
|
||||
guest.ssh_command_l2_1("lsblk").unwrap().trim(),
|
||||
vec!["vdc", "16M"],
|
||||
1
|
||||
);
|
||||
));
|
||||
|
||||
// Hotplug an extra virtio-net device through L2 VM.
|
||||
guest
|
||||
@@ -4378,35 +4490,33 @@ mod common_parallel {
|
||||
add-device path=/sys/bus/pci/devices/0000:00:09.0,id=vfio123",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(vfio_hotplug_output.contains("{\"id\":\"vfio123\",\"bdf\":\"0000:00:08.0\"}"));
|
||||
assert!(check_matched_lines_count(
|
||||
vfio_hotplug_output.trim(),
|
||||
vec!["{\"id\":\"vfio123\",\"bdf\":\"0000:00:08.0\"}"],
|
||||
1
|
||||
));
|
||||
|
||||
thread::sleep(std::time::Duration::new(10, 0));
|
||||
|
||||
// Let's also verify from the third virtio-net device passed to
|
||||
// the L2 VM. This third device has been hotplugged through the L2
|
||||
// VM, so this is our way to validate hotplug works for VFIO PCI.
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command_l2_3("grep -c VFIOTAG /proc/cmdline")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
assert!(check_matched_lines_count(
|
||||
guest.ssh_command_l2_3("cat /proc/cmdline").unwrap().trim(),
|
||||
vec!["VFIOTAG"],
|
||||
1
|
||||
);
|
||||
));
|
||||
|
||||
// Check the amount of PCI devices appearing in L2 VM.
|
||||
// There should be one more device than before, raising the count
|
||||
// up to 9 PCI devices.
|
||||
assert_eq!(
|
||||
assert!(check_lines_count(
|
||||
guest
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices | wc -l")
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
9,
|
||||
);
|
||||
.trim(),
|
||||
9
|
||||
));
|
||||
|
||||
// Let's now verify that we can correctly remove the virtio-net
|
||||
// device through the "remove-device" command responsible for
|
||||
@@ -4422,15 +4532,13 @@ mod common_parallel {
|
||||
|
||||
// Check the amount of PCI devices appearing in L2 VM is back down
|
||||
// to 8 devices.
|
||||
assert_eq!(
|
||||
assert!(check_lines_count(
|
||||
guest
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices | wc -l")
|
||||
.ssh_command_l2_1("ls /sys/bus/pci/devices")
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap_or_default(),
|
||||
8,
|
||||
);
|
||||
.trim(),
|
||||
8
|
||||
));
|
||||
|
||||
// Perform memory hotplug in L2 and validate the memory is showing
|
||||
// up as expected. In order to check, we will use the virtio-net
|
||||
@@ -5790,7 +5898,7 @@ mod common_parallel {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let mut kernels = vec![direct_kernel_boot_path()];
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let kernels = vec![direct_kernel_boot_path()];
|
||||
let kernels = [direct_kernel_boot_path()];
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
@@ -5949,6 +6057,8 @@ mod common_parallel {
|
||||
event: "device-removed".to_string(),
|
||||
device_id: Some(net_id.to_string()),
|
||||
}];
|
||||
// See: #5938
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
assert!(check_latest_events_exact(&latest_events, &event_path));
|
||||
|
||||
// Plug the virtio-net device again
|
||||
@@ -5972,6 +6082,8 @@ mod common_parallel {
|
||||
device_id: None,
|
||||
},
|
||||
];
|
||||
// See: #5938
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
assert!(check_latest_events_exact(&latest_events, &event_path));
|
||||
|
||||
// Take a snapshot from the VM
|
||||
@@ -5994,6 +6106,8 @@ mod common_parallel {
|
||||
device_id: None,
|
||||
},
|
||||
];
|
||||
// See: #5938
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
assert!(check_latest_events_exact(&latest_events, &event_path));
|
||||
});
|
||||
|
||||
@@ -6069,6 +6183,12 @@ mod common_parallel {
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Resume the VM
|
||||
assert!(remote_command(&api_socket_restored, "resume", None));
|
||||
// There is no way that we can ensure the 'write()' to the
|
||||
// event file is completed when the 'resume' request is
|
||||
// returned successfully, because the 'write()' was done
|
||||
// asynchronously from a different thread of Cloud
|
||||
// Hypervisor (e.g. the event-monitor thread).
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
let latest_events = [
|
||||
&MetaEvent {
|
||||
event: "resuming".to_string(),
|
||||
@@ -6248,6 +6368,7 @@ mod common_parallel {
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
|
||||
let kernel_path = direct_kernel_boot_path();
|
||||
let event_path = temp_event_monitor_path(&guest.tmp_dir);
|
||||
|
||||
let mut cmd = GuestCommand::new(&guest);
|
||||
cmd.args(["--cpus", "boot=1"])
|
||||
@@ -6258,6 +6379,7 @@ mod common_parallel {
|
||||
.args(["--net", guest.default_net_string().as_str()])
|
||||
.args(["--watchdog"])
|
||||
.args(["--api-socket", &api_socket])
|
||||
.args(["--event-monitor", format!("path={event_path}").as_str()])
|
||||
.capture_output();
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
@@ -6302,7 +6424,17 @@ mod common_parallel {
|
||||
{
|
||||
// Now pause the VM and remain offline for 30s
|
||||
assert!(remote_command(&api_socket, "pause", None));
|
||||
thread::sleep(std::time::Duration::new(30, 0));
|
||||
let latest_events = [
|
||||
&MetaEvent {
|
||||
event: "pausing".to_string(),
|
||||
device_id: None,
|
||||
},
|
||||
&MetaEvent {
|
||||
event: "paused".to_string(),
|
||||
device_id: None,
|
||||
},
|
||||
];
|
||||
assert!(check_latest_events_exact(&latest_events, &event_path));
|
||||
assert!(remote_command(&api_socket, "resume", None));
|
||||
|
||||
// Check no reboot
|
||||
@@ -6734,10 +6866,11 @@ mod common_parallel {
|
||||
.unwrap();
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
assert!(exec_host_command_status(
|
||||
"/usr/local/bin/spdk-nvme/rpc.py nvmf_create_transport -t VFIOUSER"
|
||||
)
|
||||
.success());
|
||||
assert!(exec_host_command_with_retries(
|
||||
"/usr/local/bin/spdk-nvme/rpc.py nvmf_create_transport -t VFIOUSER",
|
||||
3,
|
||||
std::time::Duration::new(5, 0),
|
||||
));
|
||||
assert!(exec_host_command_status(&format!(
|
||||
"/usr/local/bin/spdk-nvme/rpc.py bdev_aio_create {} test 512",
|
||||
nvme_dir.join("test-disk.raw").to_str().unwrap()
|
||||
@@ -6852,9 +6985,7 @@ mod common_parallel {
|
||||
#[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;
|
||||
}
|
||||
assert!(exec_host_command_status("lsmod | grep vdpa_sim_blk").success());
|
||||
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
@@ -7093,6 +7224,58 @@ mod common_parallel {
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn test_double_tty() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
let mut cmd = GuestCommand::new(&guest);
|
||||
let api_socket = temp_api_path(&guest.tmp_dir);
|
||||
let tty_str: &str = "console=hvc0 earlyprintk=ttyS0 ";
|
||||
// linux printk module enable console log.
|
||||
let con_dis_str: &str = "console [hvc0] enabled";
|
||||
// linux printk module disable console log.
|
||||
let con_enb_str: &str = "bootconsole [earlyser0] disabled";
|
||||
|
||||
let kernel_path = direct_kernel_boot_path();
|
||||
|
||||
cmd.args(["--cpus", "boot=1"])
|
||||
.args(["--memory", "size=512M"])
|
||||
.args(["--kernel", kernel_path.to_str().unwrap()])
|
||||
.args([
|
||||
"--cmdline",
|
||||
DIRECT_KERNEL_BOOT_CMDLINE
|
||||
.replace("console=hvc0 ", tty_str)
|
||||
.as_str(),
|
||||
])
|
||||
.capture_output()
|
||||
.default_disks()
|
||||
.default_net()
|
||||
.args(["--serial", "tty"])
|
||||
.args(["--console", "tty"])
|
||||
.args(["--api-socket", &api_socket]);
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
|
||||
let mut r = std::panic::catch_unwind(|| {
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
if r.is_ok() {
|
||||
r = std::panic::catch_unwind(|| {
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(s.contains(tty_str));
|
||||
assert!(s.contains(con_dis_str));
|
||||
assert!(s.contains(con_enb_str));
|
||||
});
|
||||
}
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
}
|
||||
|
||||
mod dbus_api {
|
||||
@@ -7929,6 +8112,7 @@ mod windows {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #6037"]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fn test_windows_guest_disk_hotplug() {
|
||||
@@ -8024,6 +8208,7 @@ mod windows {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #6037"]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
fn test_windows_guest_disk_hotplug_multi() {
|
||||
@@ -8447,8 +8632,13 @@ mod live_migration {
|
||||
if !send_success {
|
||||
let _ = send_migration.kill();
|
||||
let output = send_migration.wait_with_output().unwrap();
|
||||
eprintln!("\n\n==== Start 'send_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'send_migration' output ====\n\n",
|
||||
String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
||||
eprintln!(
|
||||
"\n\n==== Start 'send_migration' output ==== \
|
||||
\n\n---stdout---\n{}\n\n---stderr---\n{} \
|
||||
\n\n==== End 'send_migration' output ====\n\n",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
// The 'receive-migration' command should be executed successfully within the given timeout
|
||||
@@ -8464,8 +8654,13 @@ mod live_migration {
|
||||
if !receive_success {
|
||||
let _ = receive_migration.kill();
|
||||
let output = receive_migration.wait_with_output().unwrap();
|
||||
eprintln!("\n\n==== Start 'receive_migration' output ====\n\n---stdout---\n{}\n\n---stderr---\n{}\n\n==== End 'receive_migration' output ====\n\n",
|
||||
String::from_utf8_lossy(&output.stdout), String::from_utf8_lossy(&output.stderr));
|
||||
eprintln!(
|
||||
"\n\n==== Start 'receive_migration' output ==== \
|
||||
\n\n---stdout---\n{}\n\n---stderr---\n{} \
|
||||
\n\n==== End 'receive_migration' output ====\n\n",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
send_success && receive_success
|
||||
@@ -9458,51 +9653,51 @@ mod live_migration {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_basic() {
|
||||
_test_live_migration(true, false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_local() {
|
||||
_test_live_migration(true, true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #6134"]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[ignore = "See #5791"]
|
||||
fn test_live_upgrade_numa() {
|
||||
_test_live_migration_numa(true, false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #6134"]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[ignore = "See #5791"]
|
||||
fn test_live_upgrade_numa_local() {
|
||||
_test_live_migration_numa(true, true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_watchdog() {
|
||||
_test_live_migration_watchdog(true, false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_watchdog_local() {
|
||||
_test_live_migration_watchdog(true, true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_balloon() {
|
||||
_test_live_migration_balloon(true, false)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5791"]
|
||||
#[ignore = "See #6134"]
|
||||
fn test_live_upgrade_balloon_local() {
|
||||
_test_live_migration_balloon(true, true)
|
||||
}
|
||||
@@ -9515,6 +9710,7 @@ mod live_migration {
|
||||
|
||||
// Require to run ovs-dpdk tests sequentially because they rely on the same ovs-dpdk setup
|
||||
#[test]
|
||||
#[ignore = "See #5532"]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_live_migration_ovs_dpdk() {
|
||||
@@ -9529,17 +9725,17 @@ mod live_migration {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5532"]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[ignore = "See #5791"]
|
||||
fn test_live_upgrade_ovs_dpdk() {
|
||||
_test_live_migration_ovs_dpdk(true, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "See #5532"]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
#[ignore = "See #5791"]
|
||||
fn test_live_upgrade_ovs_dpdk_local() {
|
||||
_test_live_migration_ovs_dpdk(true, true);
|
||||
}
|
||||
@@ -9628,7 +9824,9 @@ mod rate_limiter {
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"\n\n==== check_rate_limit failed! ====\n\nmeasured={measured}, , lower_limit={lower_limit}, upper_limit={upper_limit}\n\n"
|
||||
"\n\n==== Start 'check_rate_limit' failed ==== \
|
||||
\n\nmeasured={measured}, , lower_limit={lower_limit}, upper_limit={upper_limit} \
|
||||
\n\n==== End 'check_rate_limit' failed ====\n\n"
|
||||
);
|
||||
|
||||
false
|
||||
@@ -9689,9 +9887,8 @@ mod rate_limiter {
|
||||
_test_rate_limiter_net(false);
|
||||
}
|
||||
|
||||
fn _test_rate_limiter_block(bandwidth: bool) {
|
||||
fn _test_rate_limiter_block(bandwidth: bool, num_queues: u32) {
|
||||
let test_timeout = 10;
|
||||
let num_queues = 1;
|
||||
let fio_ops = FioOps::RandRW;
|
||||
|
||||
let bw_size = if bandwidth {
|
||||
@@ -9718,11 +9915,11 @@ mod rate_limiter {
|
||||
|
||||
let test_blk_params = if bandwidth {
|
||||
format!(
|
||||
"path={blk_rate_limiter_test_img},bw_size={bw_size},bw_refill_time={bw_refill_time}"
|
||||
"path={blk_rate_limiter_test_img},num_queues={num_queues},bw_size={bw_size},bw_refill_time={bw_refill_time}"
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"path={blk_rate_limiter_test_img},ops_size={bw_size},ops_refill_time={bw_refill_time}"
|
||||
"path={blk_rate_limiter_test_img},num_queues={num_queues},ops_size={bw_size},ops_refill_time={bw_refill_time}"
|
||||
)
|
||||
};
|
||||
|
||||
@@ -9775,13 +9972,137 @@ mod rate_limiter {
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
fn _test_rate_limiter_group_block(bandwidth: bool, num_queues: u32, num_disks: u32) {
|
||||
let test_timeout = 10;
|
||||
let fio_ops = FioOps::RandRW;
|
||||
|
||||
let bw_size = if bandwidth {
|
||||
10485760_u64 // bytes
|
||||
} else {
|
||||
100_u64 // I/O
|
||||
};
|
||||
let bw_refill_time = 100; // ms
|
||||
let limit_rate = (bw_size * 1000) as f64 / bw_refill_time as f64;
|
||||
|
||||
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 test_img_dir = TempDir::new_with_prefix("/var/tmp/ch").unwrap();
|
||||
|
||||
let rate_limit_group_arg = if bandwidth {
|
||||
format!("id=group0,bw_size={bw_size},bw_refill_time={bw_refill_time}")
|
||||
} else {
|
||||
format!("id=group0,ops_size={bw_size},ops_refill_time={bw_refill_time}")
|
||||
};
|
||||
|
||||
let mut disk_args = vec![
|
||||
"--disk".to_string(),
|
||||
format!(
|
||||
"path={}",
|
||||
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
|
||||
),
|
||||
format!(
|
||||
"path={}",
|
||||
guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||
),
|
||||
];
|
||||
|
||||
for i in 0..num_disks {
|
||||
let test_img_path = String::from(
|
||||
test_img_dir
|
||||
.as_path()
|
||||
.join(format!("blk{}.img", i))
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
assert!(exec_host_command_output(&format!(
|
||||
"dd if=/dev/zero of={test_img_path} bs=1M count=1024"
|
||||
))
|
||||
.status
|
||||
.success());
|
||||
|
||||
disk_args.push(format!(
|
||||
"path={test_img_path},num_queues={num_queues},rate_limit_group=group0"
|
||||
));
|
||||
}
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(["--cpus", &format!("boot={}", num_queues * num_disks)])
|
||||
.args(["--memory", "size=4G"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
.args(["--rate-limit-group", &rate_limit_group_arg])
|
||||
.args(disk_args)
|
||||
.default_net()
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
let mut fio_command = format!(
|
||||
"sudo fio --name=global --output-format=json \
|
||||
--direct=1 --bs=4k --ioengine=io_uring --iodepth=64 \
|
||||
--rw={fio_ops} --runtime={test_timeout} --numjobs={num_queues}"
|
||||
);
|
||||
|
||||
// Generate additional argument for each disk:
|
||||
// --name=job0 --filename=/dev/vdc \
|
||||
// --name=job1 --filename=/dev/vdd \
|
||||
// --name=job2 --filename=/dev/vde \
|
||||
// ...
|
||||
for i in 0..num_disks {
|
||||
let c: char = 'c';
|
||||
let arg = format!(
|
||||
" --name=job{i} --filename=/dev/vd{}",
|
||||
char::from_u32((c as u32) + i).unwrap()
|
||||
);
|
||||
fio_command += &arg;
|
||||
}
|
||||
let output = guest.ssh_command(&fio_command).unwrap();
|
||||
|
||||
// Parse fio output
|
||||
let measured_rate = if bandwidth {
|
||||
parse_fio_output(&output, &fio_ops, num_queues * num_disks).unwrap()
|
||||
} else {
|
||||
parse_fio_output_iops(&output, &fio_ops, num_queues * num_disks).unwrap()
|
||||
};
|
||||
assert!(check_rate_limit(measured_rate, limit_rate, 0.1));
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_block_bandwidth() {
|
||||
_test_rate_limiter_block(true)
|
||||
_test_rate_limiter_block(true, 1);
|
||||
_test_rate_limiter_block(true, 2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_block_bandwidth() {
|
||||
_test_rate_limiter_group_block(true, 1, 1);
|
||||
_test_rate_limiter_group_block(true, 2, 1);
|
||||
_test_rate_limiter_group_block(true, 1, 2);
|
||||
_test_rate_limiter_group_block(true, 2, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_block_iops() {
|
||||
_test_rate_limiter_block(false)
|
||||
_test_rate_limiter_block(false, 1);
|
||||
_test_rate_limiter_block(false, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rate_limiter_group_block_iops() {
|
||||
_test_rate_limiter_group_block(false, 1, 1);
|
||||
_test_rate_limiter_group_block(false, 2, 1);
|
||||
_test_rate_limiter_group_block(false, 1, 2);
|
||||
_test_rate_limiter_group_block(false, 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,4 +12,4 @@ libc = "0.2.138"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
thiserror = "1.0.37"
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -5,11 +5,11 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
once_cell = "1.18.0"
|
||||
serde = { version = "1.0.168", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.107"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
once_cell = "1.19.0"
|
||||
serde = { version = "1.0.196", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.109"
|
||||
|
||||
[features]
|
||||
tracing = []
|
||||
|
||||
@@ -6,17 +6,16 @@ edition = "2021"
|
||||
build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.3.11", features = ["wrap_help","cargo"] }
|
||||
clap = { version = "4.4.7", features = ["wrap_help","cargo"] }
|
||||
block = { path = "../block" }
|
||||
env_logger = "0.10.0"
|
||||
env_logger = "0.10.1"
|
||||
epoll = "4.3.3"
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost = { version = "0.8.1", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.10.1"
|
||||
vhost = { version = "0.10.0", features = ["vhost-user-backend"] }
|
||||
vhost-user-backend = "0.13.1"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.9.0"
|
||||
vm-memory = "0.12.2"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
virtio-queue = "0.11.0"
|
||||
vm-memory = "0.14.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -58,6 +58,7 @@ impl<D: Read + Seek + Write + Send> DiskFile for D {}
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
type VhostUserBackendResult<T> = std::result::Result<T, std::io::Error>;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
/// Failed to create kill eventfd
|
||||
@@ -299,9 +300,10 @@ impl VhostUserBlkBackend {
|
||||
}
|
||||
}
|
||||
|
||||
impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, AtomicBitmap>
|
||||
for VhostUserBlkBackend
|
||||
{
|
||||
impl VhostUserBackendMut for VhostUserBlkBackend {
|
||||
type Bitmap = AtomicBitmap;
|
||||
type Vring = VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>;
|
||||
|
||||
fn num_queues(&self) -> usize {
|
||||
self.config.num_queues as usize
|
||||
}
|
||||
@@ -350,7 +352,7 @@ impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, Atomic
|
||||
evset: EventSet,
|
||||
vrings: &[VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
thread_id: usize,
|
||||
) -> VhostUserBackendResult<bool> {
|
||||
) -> VhostUserBackendResult<()> {
|
||||
if evset != EventSet::IN {
|
||||
return Err(Error::HandleEventNotEpollIn.into());
|
||||
}
|
||||
@@ -394,7 +396,7 @@ impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, Atomic
|
||||
thread.process_queue(&mut vring);
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(Error::HandleEventUnknownEvent.into()),
|
||||
}
|
||||
|
||||
@@ -6,16 +6,15 @@ edition = "2021"
|
||||
build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.3.11", features = ["wrap_help","cargo"] }
|
||||
env_logger = "0.10.0"
|
||||
clap = { version = "4.4.7", features = ["wrap_help","cargo"] }
|
||||
env_logger = "0.10.1"
|
||||
epoll = "4.3.3"
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost = { version = "0.8.1", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.10.1"
|
||||
vhost = { version = "0.10.0", features = ["vhost-user-backend"] }
|
||||
vhost-user-backend = "0.13.1"
|
||||
virtio-bindings = "0.2.0"
|
||||
vm-memory = "0.12.2"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
vm-memory = "0.14.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
@@ -158,9 +158,10 @@ impl VhostUserNetBackend {
|
||||
}
|
||||
}
|
||||
|
||||
impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, AtomicBitmap>
|
||||
for VhostUserNetBackend
|
||||
{
|
||||
impl VhostUserBackendMut for VhostUserNetBackend {
|
||||
type Bitmap = AtomicBitmap;
|
||||
type Vring = VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>;
|
||||
|
||||
fn num_queues(&self) -> usize {
|
||||
self.num_queues
|
||||
}
|
||||
@@ -203,7 +204,7 @@ impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, Atomic
|
||||
_evset: EventSet,
|
||||
vrings: &[VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>],
|
||||
thread_id: usize,
|
||||
) -> VhostUserBackendResult<bool> {
|
||||
) -> VhostUserBackendResult<()> {
|
||||
let mut thread = self.threads[thread_id].lock().unwrap();
|
||||
match device_event {
|
||||
0 => {
|
||||
@@ -245,7 +246,7 @@ impl VhostUserBackendMut<VringRwLock<GuestMemoryAtomic<GuestMemoryMmap>>, Atomic
|
||||
_ => return Err(Error::HandleEventUnknownEvent.into()),
|
||||
}
|
||||
|
||||
Ok(false)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn exit_event(&self, thread_index: usize) -> Option<EventFd> {
|
||||
|
||||
@@ -8,31 +8,31 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.75"
|
||||
anyhow = "1.0.79"
|
||||
arc-swap = "1.5.1"
|
||||
block = { path = "../block" }
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.3"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
libc = "0.2.147"
|
||||
log = "0.4.17"
|
||||
libc = "0.2.153"
|
||||
log = "0.4.20"
|
||||
net_gen = { path = "../net_gen" }
|
||||
net_util = { path = "../net_util" }
|
||||
pci = { path = "../pci" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
seccompiler = "0.4.0"
|
||||
serde = { version = "1.0.168", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
serde = { version = "1.0.196", features = ["derive"] }
|
||||
serde_json = "1.0.109"
|
||||
serial_buffer = { path = "../serial_buffer" }
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.8.1", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
|
||||
thiserror = "1.0.52"
|
||||
versionize = "0.2.0"
|
||||
versionize_derive = "0.1.6"
|
||||
vhost = { version = "0.10.0", features = ["vhost-user-frontend", "vhost-user-backend", "vhost-kern", "vhost-vdpa"] }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.9.0"
|
||||
virtio-queue = "0.11.0"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.12.2", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.14.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vmm-sys-util = "0.12.1"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user