mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
272 Commits
stable/v30
...
v33.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e0e632361 | ||
|
|
1c9df58440 | ||
|
|
1917e86206 | ||
|
|
787f5085b6 | ||
|
|
fec39ccf51 | ||
|
|
115085eb9e | ||
|
|
802e9009b9 | ||
|
|
37fbece885 | ||
|
|
ec6e87479f | ||
|
|
5b51024ef7 | ||
|
|
99a98f270d | ||
|
|
c0af33a4c9 | ||
|
|
0cf868b5c1 | ||
|
|
3da60dfa5e | ||
|
|
1c8a91940e | ||
|
|
8c117a8117 | ||
|
|
7d0aa1fd02 | ||
|
|
a0190b16aa | ||
|
|
1bd8eb68ff | ||
|
|
8363eddd97 | ||
|
|
70aa5bc231 | ||
|
|
b8ce1816e9 | ||
|
|
43eed4861f | ||
|
|
268c4ea214 | ||
|
|
29a0ddc58e | ||
|
|
4079e4f1ad | ||
|
|
fba0b5f93c | ||
|
|
05cc5f596c | ||
|
|
c1b33329db | ||
|
|
402a24a688 | ||
|
|
0809e7f675 | ||
|
|
a718716831 | ||
|
|
5a9dd7489c | ||
|
|
dec8d619d4 | ||
|
|
c39cdb3c1f | ||
|
|
26ae8b6d5c | ||
|
|
de31b3fadc | ||
|
|
b06ad85604 | ||
|
|
8d89736c68 | ||
|
|
55ee8eb482 | ||
|
|
1017157bb6 | ||
|
|
499989fb17 | ||
|
|
ce0f30bb54 | ||
|
|
fce202a90c | ||
|
|
95626ae564 | ||
|
|
1e1012c31b | ||
|
|
56207dc3a0 | ||
|
|
57fdaa3a39 | ||
|
|
19c5c0af9f | ||
|
|
e26e7b4d72 | ||
|
|
e8d6c9ecb0 | ||
|
|
0712027eb1 | ||
|
|
7ea5d7a416 | ||
|
|
7023d4ff84 | ||
|
|
5f31ad319e | ||
|
|
5083549afe | ||
|
|
beed5e5d6d | ||
|
|
7feb25daf0 | ||
|
|
f2574897cd | ||
|
|
2698924c0d | ||
|
|
6bd4927d11 | ||
|
|
f485922b78 | ||
|
|
1faaa2cd0a | ||
|
|
6c630f4908 | ||
|
|
3b39c41a01 | ||
|
|
309e346c4c | ||
|
|
3f6833b315 | ||
|
|
a862c804ba | ||
|
|
83914d80a2 | ||
|
|
a7aecb5eee | ||
|
|
a64d27f841 | ||
|
|
7a458d85d1 | ||
|
|
a92d852848 | ||
|
|
0664647109 | ||
|
|
f2c813e1cf | ||
|
|
f00df25d40 | ||
|
|
c016a0d4d3 | ||
|
|
5c96fbb19b | ||
|
|
b955f09b80 | ||
|
|
79ad6f8536 | ||
|
|
be4f04a906 | ||
|
|
f8415debe9 | ||
|
|
9014a5e59c | ||
|
|
612621bb46 | ||
|
|
18e1d2caf5 | ||
|
|
4be406a308 | ||
|
|
7bf2a2c382 | ||
|
|
7df80220ec | ||
|
|
84d2511de0 | ||
|
|
374263ddac | ||
|
|
7b76b6b61e | ||
|
|
e06f12673b | ||
|
|
89e658d9ff | ||
|
|
5ac68534b1 | ||
|
|
6acceaa87c | ||
|
|
a3898fd8e1 | ||
|
|
7026622c24 | ||
|
|
41e5384f15 | ||
|
|
681a30bd15 | ||
|
|
1976157761 | ||
|
|
0b1e626fe3 | ||
|
|
79bc42f3c2 | ||
|
|
eca75dcfc9 | ||
|
|
600d1664ee | ||
|
|
e6208d1c0e | ||
|
|
cf635c64d7 | ||
|
|
42ca292dce | ||
|
|
b7338c96eb | ||
|
|
bf4af14e73 | ||
|
|
24a3505f0b | ||
|
|
20f3691474 | ||
|
|
c56a3ce59a | ||
|
|
18f7a37b48 | ||
|
|
98496434b9 | ||
|
|
0b2994a6e3 | ||
|
|
553e6857bd | ||
|
|
083ce323c0 | ||
|
|
8fff4c1af3 | ||
|
|
35ecfb6ec5 | ||
|
|
a61a013311 | ||
|
|
b509fd94cd | ||
|
|
631af8a4f7 | ||
|
|
aa14fe214a | ||
|
|
45e3f49bba | ||
|
|
03db406645 | ||
|
|
ba1e89139a | ||
|
|
21d40d7489 | ||
|
|
c90a0ffff6 | ||
|
|
dc7931f592 | ||
|
|
841627f10a | ||
|
|
97fdb65012 | ||
|
|
d17d70fae1 | ||
|
|
71d1296d09 | ||
|
|
0d58e51a3a | ||
|
|
97012c511d | ||
|
|
c10e2a79b1 | ||
|
|
f3870ae638 | ||
|
|
3c0b389c82 | ||
|
|
9881c94f84 | ||
|
|
ceb8151747 | ||
|
|
2554f2a8d4 | ||
|
|
036af673e6 | ||
|
|
990362e314 | ||
|
|
83d57d3cce | ||
|
|
a0babfb9c1 | ||
|
|
3394a59466 | ||
|
|
f8e0376f6d | ||
|
|
6379074264 | ||
|
|
5dbc72948f | ||
|
|
04d111ee15 | ||
|
|
a9623c7a28 | ||
|
|
4baf85857a | ||
|
|
e3d2917d5f | ||
|
|
a84b540b65 | ||
|
|
8eb162e3d7 | ||
|
|
2804608a1c | ||
|
|
e0125653b1 | ||
|
|
e431a48201 | ||
|
|
c143cb3af0 | ||
|
|
b6feae0ace | ||
|
|
520aff2efc | ||
|
|
41880919a0 | ||
|
|
865291d840 | ||
|
|
346ee09e6b | ||
|
|
59012ccc6e | ||
|
|
3f17f4657b | ||
|
|
086ca9b935 | ||
|
|
9b724303ac | ||
|
|
948573db0d | ||
|
|
0352846af2 | ||
|
|
8b3f0043b0 | ||
|
|
9d532acab6 | ||
|
|
df2a7c1764 | ||
|
|
3f5dac988f | ||
|
|
3096f1d42f | ||
|
|
42a4e593ce | ||
|
|
b56da6ee24 | ||
|
|
90dcbc3232 | ||
|
|
f3522e85fc | ||
|
|
d3ac6a85e0 | ||
|
|
38a1b45783 | ||
|
|
e9841db486 | ||
|
|
c1f555cde3 | ||
|
|
505f4dfa53 | ||
|
|
67ad3ff1ba | ||
|
|
755cabea4c | ||
|
|
1ed4898d28 | ||
|
|
a807b91f86 | ||
|
|
f6236087d8 | ||
|
|
95f83320b1 | ||
|
|
dcc858a403 | ||
|
|
57ea412c64 | ||
|
|
e32c9525c0 | ||
|
|
2b4f60e57b | ||
|
|
5736205cf0 | ||
|
|
a8d1849485 | ||
|
|
55937f63bc | ||
|
|
426d5d6dd0 | ||
|
|
3f3d07b3dc | ||
|
|
296cb909f4 | ||
|
|
e7d52fc736 | ||
|
|
a598b935f2 | ||
|
|
1c0b6f1090 | ||
|
|
1b12790c13 | ||
|
|
bd307dcab5 | ||
|
|
83d757d89a | ||
|
|
1b8e7ac06c | ||
|
|
389e4fe8be | ||
|
|
06a9c3b839 | ||
|
|
36cf46e381 | ||
|
|
1efdea7466 | ||
|
|
e662a2e12c | ||
|
|
5496bd5dfb | ||
|
|
e655de1e39 | ||
|
|
a55a642b70 | ||
|
|
ded8959b9a | ||
|
|
53e49636ca | ||
|
|
0b0f3c69f0 | ||
|
|
6650f553bd | ||
|
|
c5bca514b9 | ||
|
|
c4106c0592 | ||
|
|
61f89e7dcc | ||
|
|
7a4be1534f | ||
|
|
cf0c4e07b6 | ||
|
|
36ec53c4a0 | ||
|
|
c7997ea4e5 | ||
|
|
b2d3aba19c | ||
|
|
9cd97bb64e | ||
|
|
868fdf9dfe | ||
|
|
12729eb034 | ||
|
|
a062401be6 | ||
|
|
09cc139b53 | ||
|
|
4635ebd4b2 | ||
|
|
ca96ff601b | ||
|
|
feb523ef78 | ||
|
|
7e47464a48 | ||
|
|
4c4f79c831 | ||
|
|
0fd701ac75 | ||
|
|
64924d5c2b | ||
|
|
9c11927305 | ||
|
|
b13d0e53c5 | ||
|
|
6001240ca1 | ||
|
|
9534604ef3 | ||
|
|
c152f9f6bc | ||
|
|
325e62372d | ||
|
|
9421884334 | ||
|
|
fcd09946b7 | ||
|
|
a20e481abe | ||
|
|
6e4374c392 | ||
|
|
44452cbe22 | ||
|
|
7b2ebd2fa5 | ||
|
|
8a0f6014ce | ||
|
|
d78da5d252 | ||
|
|
b35a94d83c | ||
|
|
961319d8ad | ||
|
|
b97f929706 | ||
|
|
b71564f284 | ||
|
|
f2be30f699 | ||
|
|
b14216e854 | ||
|
|
3498e67bda | ||
|
|
24d163b244 | ||
|
|
90697d4ae0 | ||
|
|
73c4156775 | ||
|
|
02f774824b | ||
|
|
74cd3d0dc2 | ||
|
|
85962099c7 | ||
|
|
04ee1efa70 | ||
|
|
5258a870e0 | ||
|
|
76d6d28f3e | ||
|
|
5132e3b907 | ||
|
|
599c5280ed | ||
|
|
2f649bb6ad |
5
.github/workflows/build.yaml
vendored
5
.github/workflows/build.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
- "1.62"
|
||||
- "1.64"
|
||||
target:
|
||||
- x86_64-unknown-linux-gnu
|
||||
- x86_64-unknown-linux-musl
|
||||
@@ -42,6 +42,9 @@ jobs:
|
||||
- name: Build (default features + tdx)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "tdx" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + dbus_api)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "dbus_api" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
- name: Build (default features + guest_debug)
|
||||
run: cargo rustc --locked --bin cloud-hypervisor --features "guest_debug" -- -D warnings -D clippy::undocumented_unsafe_blocks
|
||||
|
||||
|
||||
20
.github/workflows/docker-image.yaml
vendored
20
.github/workflows/docker-image.yaml
vendored
@@ -7,6 +7,10 @@ on:
|
||||
pull_request:
|
||||
paths: resources/Dockerfile
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -20,19 +24,19 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Login to DockerHub
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
uses: docker/login-action@v1
|
||||
- name: Login to ghcr
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: cloudhypervisor/dev
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
# generate Docker tags based on the following events/attributes
|
||||
tags: |
|
||||
type=raw,value={{date 'YYYYMMDD'}}-0
|
||||
|
||||
26
.github/workflows/hadolint.yaml
vendored
Normal file
26
.github/workflows/hadolint.yaml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Lint Dockerfile
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
pull_request:
|
||||
paths:
|
||||
- resources/Dockerfile
|
||||
|
||||
jobs:
|
||||
hadolint:
|
||||
name: Run Hadolint Dockerfile Linter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Lint Dockerfile
|
||||
uses: hadolint/hadolint-action@master
|
||||
with:
|
||||
dockerfile: ./resources/Dockerfile
|
||||
format: tty
|
||||
no-fail: false
|
||||
verbose: true
|
||||
failure-threshold: info
|
||||
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
@@ -16,29 +16,29 @@ jobs:
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- name: Install Rust toolchain (x86_64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: x86_64-unknown-linux-musl
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
command: build
|
||||
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-gnu
|
||||
- name: Static Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
command: build
|
||||
args: --all --release --no-default-features --features "kvm,mshv" --target=x86_64-unknown-linux-musl
|
||||
- name: Install Rust toolchain (aarch64-unknown-linux-musl)
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: "1.62"
|
||||
toolchain: "1.67.1"
|
||||
target: aarch64-unknown-linux-musl
|
||||
override: true
|
||||
- name: Create Release
|
||||
|
||||
1256
Cargo.lock
generated
1256
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
21
Cargo.toml
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cloud-hypervisor"
|
||||
version = "30.1.0"
|
||||
version = "33.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.62"
|
||||
rust-version = "1.64"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
@@ -29,7 +29,7 @@ strip = false
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
api_client = { path = "api_client" }
|
||||
argh = "0.1.9"
|
||||
dhat = { version = "0.3.2", optional = true }
|
||||
@@ -40,31 +40,34 @@ libc = "0.2.139"
|
||||
log = { version = "0.4.17", features = ["std"] }
|
||||
option_parser = { path = "option_parser" }
|
||||
seccompiler = "0.3.0"
|
||||
serde_json = "1.0.93"
|
||||
signal-hook = "0.3.14"
|
||||
thiserror = "1.0.38"
|
||||
serde_json = "1.0.96"
|
||||
signal-hook = "0.3.15"
|
||||
thiserror = "1.0.40"
|
||||
tpm = { path = "tpm"}
|
||||
tracer = { path = "tracer" }
|
||||
vmm = { path = "vmm" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.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" }
|
||||
vhost = { git = "https://github.com/rust-vmm/vhost", branch = "main" }
|
||||
|
||||
[dev-dependencies]
|
||||
dirs = "4.0.0"
|
||||
dirs = "5.0.0"
|
||||
net_util = { path = "net_util" }
|
||||
once_cell = "1.17.1"
|
||||
serde_json = "1.0.93"
|
||||
serde_json = "1.0.96"
|
||||
test_infra = { path = "test_infra" }
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
[features]
|
||||
default = ["kvm"]
|
||||
dbus_api = ["zbus", "vmm/dbus_api"]
|
||||
dhat-heap = ["dhat"] # For heap profiling
|
||||
guest_debug = ["vmm/guest_debug"]
|
||||
kvm = ["vmm/kvm"]
|
||||
|
||||
15
README.md
15
README.md
@@ -113,7 +113,7 @@ Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) or an
|
||||
edk2 UEFI firmware called `CLOUDHV` / `CLOUDHV_EFI`.)
|
||||
|
||||
Binary builds of the firmware files are available for the latest release of
|
||||
[Rust Hyperivor
|
||||
[Rust Hypervisor
|
||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware/releases/latest)
|
||||
and [our edk2
|
||||
repository](https://github.com/cloud-hypervisor/edk2/releases/latest)
|
||||
@@ -124,7 +124,7 @@ may be required.
|
||||
### Firmware Booting
|
||||
|
||||
Cloud Hypervisor supports booting disk images containing all needed components
|
||||
to run cloud workloads, a.k.a. cloud images.
|
||||
to run cloud workloads, a.k.a. cloud images.
|
||||
|
||||
The following sample commands will download an Ubuntu Cloud image, converting
|
||||
it into a format that Cloud Hypervisor can use and a firmware to boot the image
|
||||
@@ -140,7 +140,10 @@ The Ubuntu cloud images do not ship with a default password so it necessary to
|
||||
use a `cloud-init` disk image to customise the image on the first boot. A basic
|
||||
`cloud-init` image is generated by this [script](scripts/create-cloud-init.sh).
|
||||
This seeds the image with a default username/password of `cloud/cloud123`. It
|
||||
is only necessary to add this disk image on the first boot.
|
||||
is only necessary to add this disk image on the first boot. Script also assigns
|
||||
default IP address using `test_data/cloud-init/ubuntu/local/network-config` details
|
||||
with `--net "mac=12:34:56:78:90:ab,tap="` option. Then the matching mac address
|
||||
interface will be enabled as per `network-config` details.
|
||||
|
||||
```shell
|
||||
$ sudo setcap cap_net_admin+ep ./cloud-hypervisor
|
||||
@@ -178,7 +181,7 @@ To build the kernel:
|
||||
|
||||
```shell
|
||||
# Clone the Cloud Hypervisor Linux branch
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.1.6 linux-cloud-hypervisor
|
||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-6.2 linux-cloud-hypervisor
|
||||
$ pushd linux-cloud-hypervisor
|
||||
# Use the x86-64 cloud-hypervisor kernel config to build your kernel for x86-64
|
||||
$ wget https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/main/resources/linux-config-x86_64
|
||||
@@ -372,8 +375,8 @@ are all equal and welcome means of contribution. See the
|
||||
|
||||
## Slack
|
||||
|
||||
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI)
|
||||
and [join us on Slack](https://cloud-hypervisor.slack.com/).
|
||||
Get an [invite to our Slack channel](https://join.slack.com/t/cloud-hypervisor/shared_invite/enQtNjY3MTE3MDkwNDQ4LWQ1MTA1ZDVmODkwMWQ1MTRhYzk4ZGNlN2UwNTI3ZmFlODU0OTcwOWZjMTkwZDExYWE3YjFmNzgzY2FmNDAyMjI),
|
||||
[join us on Slack](https://cloud-hypervisor.slack.com/), and [participate in our community activities](https://cloud-hypervisor.slack.com/archives/C04R5DUQVBN).
|
||||
|
||||
## Mailing list
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@ default = []
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.9.0", features = ["elf", "bzimage", "pe"] }
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.38"
|
||||
uuid = "1.3.0"
|
||||
versionize = "0.1.9"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.40"
|
||||
uuid = "1.3.4"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ use super::layout::{
|
||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||
};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||
|
||||
@@ -40,8 +42,12 @@ const VIRTIO_IOMMU_PHANDLE: u32 = 5;
|
||||
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
|
||||
// This is a value for uniquely identifying the FDT node containing the first vCPU.
|
||||
// The last number of vCPU phandle depends on the number of vCPUs.
|
||||
const FIRST_VCPU_PHANDLE: u32 = 6;
|
||||
const FIRST_VCPU_PHANDLE: u32 = 8;
|
||||
|
||||
// This is a value for uniquely identifying the FDT node containing the L2 cache info
|
||||
const L2_CACHE_PHANDLE: u32 = 6;
|
||||
// This is a value for uniquely identifying the FDT node containing the L3 cache info
|
||||
const L3_CACHE_PHANDLE: u32 = 7;
|
||||
// Read the documentation specified when appending the root node to the FDT.
|
||||
const ADDRESS_CELLS: u32 = 0x2;
|
||||
const SIZE_CELLS: u32 = 0x2;
|
||||
@@ -81,6 +87,97 @@ pub enum Error {
|
||||
}
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub enum CacheLevel {
|
||||
/// L1 data cache
|
||||
L1D = 0,
|
||||
/// L1 instruction cache
|
||||
L1I = 1,
|
||||
/// L2 cache
|
||||
L2 = 2,
|
||||
/// L3 cache
|
||||
L3 = 3,
|
||||
}
|
||||
|
||||
/// NOTE: CACHE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/size".
|
||||
pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/size",
|
||||
CacheLevel::L1I => file_directory += "/index1/size",
|
||||
CacheLevel::L2 => file_directory += "/index2/size",
|
||||
CacheLevel::L3 => file_directory += "/index3/size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
// The content of the file is as simple as a size, like: "32K"
|
||||
let src = src.trim();
|
||||
let src_digits: u32 = src[0..src.len() - 1].parse().unwrap();
|
||||
let src_unit = &src[src.len() - 1..];
|
||||
|
||||
src_digits
|
||||
* match src_unit {
|
||||
"K" => 1024,
|
||||
"M" => 1024u32.pow(2),
|
||||
"G" => 1024u32.pow(3),
|
||||
_ => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE COHERENCY LINE SIZE file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size".
|
||||
pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/coherency_line_size",
|
||||
CacheLevel::L1I => file_directory += "/index1/coherency_line_size",
|
||||
CacheLevel::L2 => file_directory += "/index2/coherency_line_size",
|
||||
CacheLevel::L3 => file_directory += "/index3/coherency_line_size",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// NOTE: CACHE NUMBER OF SETS file directory example,
|
||||
/// "/sys/devices/system/cpu/cpu0/cache/index0/number_of_sets".
|
||||
pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
|
||||
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
|
||||
match cache_level {
|
||||
CacheLevel::L1D => file_directory += "/index0/number_of_sets",
|
||||
CacheLevel::L1I => file_directory += "/index1/number_of_sets",
|
||||
CacheLevel::L2 => file_directory += "/index2/number_of_sets",
|
||||
CacheLevel::L3 => file_directory += "/index3/number_of_sets",
|
||||
}
|
||||
|
||||
let file_path = Path::new(&file_directory);
|
||||
if !file_path.exists() {
|
||||
error!("File: {} not exist.", file_directory);
|
||||
0
|
||||
} else {
|
||||
info!("File: {} exist.", file_directory);
|
||||
|
||||
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
|
||||
src.trim().parse::<u32>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the flattened device tree for this aarch64 VM.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
|
||||
@@ -159,6 +256,54 @@ fn create_cpu_nodes(
|
||||
|
||||
let num_cpus = vcpu_mpidr.len();
|
||||
|
||||
// Add cache info.
|
||||
// L1 Data Cache Info.
|
||||
let mut l1_d_cache_size: u32 = 0;
|
||||
let mut l1_d_cache_line_size: u32 = 0;
|
||||
let mut l1_d_cache_sets: u32 = 0;
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
let mut l1_i_cache_size: u32 = 0;
|
||||
let mut l1_i_cache_line_size: u32 = 0;
|
||||
let mut l1_i_cache_sets: u32 = 0;
|
||||
|
||||
// L2 Cache Info.
|
||||
let mut l2_cache_size: u32 = 0;
|
||||
let mut l2_cache_line_size: u32 = 0;
|
||||
let mut l2_cache_sets: u32 = 0;
|
||||
|
||||
// L3 Cache Info.
|
||||
let mut l3_cache_size: u32 = 0;
|
||||
let mut l3_cache_line_size: u32 = 0;
|
||||
let mut l3_cache_sets: u32 = 0;
|
||||
|
||||
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
|
||||
let cache_exist: bool = cache_path.exists();
|
||||
if !cache_exist {
|
||||
error!("cache sysfs system does not exist.");
|
||||
} else {
|
||||
info!("cache sysfs system exists.");
|
||||
// L1 Data Cache Info.
|
||||
l1_d_cache_size = get_cache_size(CacheLevel::L1D);
|
||||
l1_d_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1D);
|
||||
l1_d_cache_sets = get_cache_number_of_sets(CacheLevel::L1D);
|
||||
|
||||
// L1 Instruction Cache Info.
|
||||
l1_i_cache_size = get_cache_size(CacheLevel::L1I);
|
||||
l1_i_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1I);
|
||||
l1_i_cache_sets = get_cache_number_of_sets(CacheLevel::L1I);
|
||||
|
||||
// L2 Cache Info.
|
||||
l2_cache_size = get_cache_size(CacheLevel::L2);
|
||||
l2_cache_line_size = get_cache_coherency_line_size(CacheLevel::L2);
|
||||
l2_cache_sets = get_cache_number_of_sets(CacheLevel::L2);
|
||||
|
||||
// L3 Cache Info.
|
||||
l3_cache_size = get_cache_size(CacheLevel::L3);
|
||||
l3_cache_line_size = get_cache_coherency_line_size(CacheLevel::L3);
|
||||
l3_cache_sets = get_cache_number_of_sets(CacheLevel::L3);
|
||||
}
|
||||
|
||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||
let cpu_name = format!("cpu@{cpu_id:x}");
|
||||
let cpu_node = fdt.begin_node(&cpu_name)?;
|
||||
@@ -173,6 +318,21 @@ fn create_cpu_nodes(
|
||||
fdt.property_u32("reg", (mpidr & 0x7FFFFF) as u32)?;
|
||||
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?;
|
||||
|
||||
if cache_exist && l1_d_cache_size != 0 && l1_i_cache_size != 0 {
|
||||
// Add cache info.
|
||||
fdt.property_u32("d-cache-size", l1_d_cache_size)?;
|
||||
fdt.property_u32("d-cache-line-size", l1_d_cache_line_size)?;
|
||||
fdt.property_u32("d-cache-sets", l1_d_cache_sets)?;
|
||||
|
||||
fdt.property_u32("i-cache-size", l1_i_cache_size)?;
|
||||
fdt.property_u32("i-cache-line-size", l1_i_cache_line_size)?;
|
||||
fdt.property_u32("i-cache-sets", l1_i_cache_sets)?;
|
||||
|
||||
if l2_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L2_CACHE_PHANDLE)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Add `numa-node-id` property if there is any numa config.
|
||||
if numa_nodes.len() > 1 {
|
||||
for numa_node_idx in 0..numa_nodes.len() {
|
||||
@@ -186,6 +346,36 @@ fn create_cpu_nodes(
|
||||
fdt.end_node(cpu_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l2_cache_size != 0 {
|
||||
let l2_cache_name = "l2-cache0";
|
||||
let l2_cache_node = fdt.begin_node(l2_cache_name)?;
|
||||
fdt.property_u32("phandle", L2_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_u32("cache-size", l2_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l2_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l2_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 2)?;
|
||||
|
||||
if l3_cache_size != 0 {
|
||||
fdt.property_u32("next-level-cache", L3_CACHE_PHANDLE)?;
|
||||
}
|
||||
|
||||
fdt.end_node(l2_cache_node)?;
|
||||
}
|
||||
|
||||
if cache_exist && l3_cache_size != 0 {
|
||||
let l3_cache_name = "l3-cache0";
|
||||
let l3_cache_node = fdt.begin_node(l3_cache_name)?;
|
||||
fdt.property_u32("phandle", L3_CACHE_PHANDLE)?;
|
||||
fdt.property_string("compatible", "cache")?;
|
||||
fdt.property_null("cache-unified")?;
|
||||
fdt.property_u32("cache-size", l3_cache_size)?;
|
||||
fdt.property_u32("cache-line-size", l3_cache_line_size)?;
|
||||
fdt.property_u32("cache-sets", l3_cache_sets)?;
|
||||
fdt.property_u32("cache-level", 3)?;
|
||||
fdt.end_node(l3_cache_node)?;
|
||||
}
|
||||
|
||||
if let Some(topology) = vcpu_topology {
|
||||
let (threads_per_core, cores_per_package, packages) = topology;
|
||||
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
||||
@@ -260,32 +450,86 @@ fn create_memory_node(
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
} else {
|
||||
let last_addr = guest_mem.last_addr().raw_value();
|
||||
if last_addr < super::layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
// Case 1: all RAM is under the hole
|
||||
let mem_size = last_addr - super::layout::RAM_START.raw_value() + 1;
|
||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
||||
let memory_node = fdt.begin_node("memory")?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
} else {
|
||||
// Case 2: RAM is split by the hole
|
||||
// Region 1: RAM before the hole
|
||||
let mem_size = super::layout::MEM_32BIT_RESERVED_START.raw_value()
|
||||
- super::layout::RAM_START.raw_value();
|
||||
let mem_reg_prop = [super::layout::RAM_START.raw_value(), mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", super::layout::RAM_START.raw_value());
|
||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||
let ram_regions = {
|
||||
let mut ram_regions = Vec::new();
|
||||
let mut current_start = guest_mem
|
||||
.iter()
|
||||
.next()
|
||||
.map(GuestMemoryRegion::start_addr)
|
||||
.expect("GuestMemory must have one memory region at least")
|
||||
.raw_value();
|
||||
let mut current_end = current_start;
|
||||
|
||||
for (start, size) in guest_mem
|
||||
.iter()
|
||||
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||
{
|
||||
if current_end == start {
|
||||
// This zone is continuous with the previous one.
|
||||
current_end += size;
|
||||
} else {
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
current_start = start;
|
||||
current_end = start + size;
|
||||
}
|
||||
}
|
||||
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
ram_regions
|
||||
};
|
||||
|
||||
if ram_regions.len() > 2 {
|
||||
panic!(
|
||||
"There should be up to two non-continuous regions, devidided by the
|
||||
gap at the end of 32bit address space."
|
||||
);
|
||||
}
|
||||
|
||||
// Create the memory node for memory region before the gap
|
||||
{
|
||||
let (first_region_start, first_region_end) = ram_regions
|
||||
.first()
|
||||
.expect("There should be at last one memory region");
|
||||
let ram_start = super::layout::RAM_START.raw_value();
|
||||
let mem_32bit_reserved_start = super::layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||
|
||||
if !((first_region_start <= &ram_start)
|
||||
&& (first_region_end > &ram_start)
|
||||
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||
{
|
||||
panic!(
|
||||
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||
ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||
first_region_start, first_region_end, ram_start, mem_32bit_reserved_start
|
||||
);
|
||||
}
|
||||
|
||||
let mem_size = first_region_end - ram_start;
|
||||
let mem_reg_prop = [ram_start, mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", ram_start);
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
fdt.end_node(memory_node)?;
|
||||
}
|
||||
|
||||
// Region 2: RAM after the hole
|
||||
let mem_size = last_addr - super::layout::RAM_64BIT_START.raw_value() + 1;
|
||||
let mem_reg_prop = [super::layout::RAM_64BIT_START.raw_value(), mem_size];
|
||||
let memory_node_name =
|
||||
format!("memory@{:x}", super::layout::RAM_64BIT_START.raw_value());
|
||||
// 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 = super::layout::RAM_64BIT_START.raw_value();
|
||||
|
||||
if second_region_start != &ram_64bit_start {
|
||||
panic!(
|
||||
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||
second_region_start, ram_64bit_start
|
||||
);
|
||||
}
|
||||
|
||||
let mem_size = second_region_end - ram_64bit_start;
|
||||
let mem_reg_prop = [ram_64bit_start, mem_size];
|
||||
let memory_node_name = format!("memory@{:x}", ram_64bit_start);
|
||||
let memory_node = fdt.begin_node(&memory_node_name)?;
|
||||
fdt.property_string("device_type", "memory")?;
|
||||
fdt.property_array_u64("reg", &mem_reg_prop)?;
|
||||
|
||||
@@ -19,7 +19,9 @@ use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic, GuestUsize};
|
||||
use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryAtomic};
|
||||
|
||||
pub const _NSIG: i32 = 65;
|
||||
|
||||
/// Errors thrown while configuring aarch64 system.
|
||||
#[derive(Debug)]
|
||||
@@ -81,8 +83,8 @@ pub fn configure_vcpu(
|
||||
Ok(mpidr)
|
||||
}
|
||||
|
||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
let mut regions = vec![
|
||||
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
vec![
|
||||
// 0 MiB ~ 256 MiB: UEFI, GIC and legacy devices
|
||||
(
|
||||
GuestAddress(0),
|
||||
@@ -101,39 +103,21 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
|
||||
layout::PCI_MMCONFIG_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
];
|
||||
|
||||
let ram_32bit_space_size =
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START);
|
||||
|
||||
// RAM space
|
||||
// Case1: guest memory fits before the gap
|
||||
if size <= ram_32bit_space_size {
|
||||
regions.push((layout::RAM_START, size as usize, RegionType::Ram));
|
||||
// Case2: guest memory extends beyond the gap
|
||||
} else {
|
||||
// Push memory before the gap
|
||||
regions.push((
|
||||
// 1GiB ~ 4032 MiB: RAM before the gap
|
||||
(
|
||||
layout::RAM_START,
|
||||
ram_32bit_space_size as usize,
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
// Other memory is placed after 4GiB
|
||||
regions.push((
|
||||
layout::RAM_64BIT_START,
|
||||
(size - ram_32bit_space_size) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
}
|
||||
|
||||
// Add the 32-bit reserved memory hole as a reserved region
|
||||
regions.push((
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
));
|
||||
|
||||
regions
|
||||
),
|
||||
// 4GiB ~ inf: RAM after the gap
|
||||
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||
// Add the 32-bit reserved memory hole as a reserved region
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_RESERVED_SIZE as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||
@@ -196,11 +180,8 @@ pub fn initramfs_load_addr(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// A dummy hypervisor created only for querying the host IPA size and will
|
||||
// be freed after the query.
|
||||
let hv = hypervisor::new().unwrap();
|
||||
let host_cpu_phys_bits = hv.get_host_ipa_limit().try_into().unwrap();
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
let host_cpu_phys_bits = hypervisor.get_host_ipa_limit().try_into().unwrap();
|
||||
if host_cpu_phys_bits == 0 {
|
||||
// Host kernel does not support `get_host_ipa_limit`,
|
||||
// we return the default value 40 here.
|
||||
@@ -215,26 +196,12 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_arch_memory_regions_dram_2gb() {
|
||||
let regions = arch_memory_regions((1usize << 31) as u64); //2GB
|
||||
assert_eq!(5, regions.len());
|
||||
assert_eq!(layout::RAM_START, regions[3].0);
|
||||
assert_eq!((1usize << 31), regions[3].1);
|
||||
assert_eq!(RegionType::Ram, regions[3].2);
|
||||
assert_eq!(RegionType::Reserved, regions[4].2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arch_memory_regions_dram_4gb() {
|
||||
let regions = arch_memory_regions((1usize << 32) as u64); //4GB
|
||||
let ram_32bit_space_size =
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::RAM_START) as usize;
|
||||
fn test_arch_memory_regions_dram() {
|
||||
let regions = arch_memory_regions();
|
||||
assert_eq!(6, regions.len());
|
||||
assert_eq!(layout::RAM_START, regions[3].0);
|
||||
assert_eq!(ram_32bit_space_size, regions[3].1);
|
||||
assert_eq!(RegionType::Ram, regions[3].2);
|
||||
assert_eq!(RegionType::Reserved, regions[5].2);
|
||||
assert_eq!(RegionType::Ram, regions[4].2);
|
||||
assert_eq!(((1usize << 32) - ram_32bit_space_size), regions[4].1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
// Copyright 2022 Arm Limited (or its affiliates). All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
///
|
||||
/// AArch64 system register encoding:
|
||||
/// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
|
||||
///
|
||||
/// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
||||
/// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
/// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
|
||||
/// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
///
|
||||
/// Notes:
|
||||
/// - L and Rt are reserved as implementation defined fields, ignored.
|
||||
///
|
||||
// AArch64 system register encoding:
|
||||
// See https://developer.arm.com/documentation/ddi0487 (chapter D12)
|
||||
//
|
||||
// 31 22 21 20 19 18 16 15 12 11 8 7 5 4 0
|
||||
// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
// |1101010100| L | op0 | op1 | CRn | CRm | op2 | Rt |
|
||||
// +----------+---+-----+-----+-----+-----+-----+----+
|
||||
//
|
||||
// Notes:
|
||||
// - L and Rt are reserved as implementation defined fields, ignored.
|
||||
|
||||
const SYSREG_HEAD: u32 = 0b1101010100u32 << 22;
|
||||
const SYSREG_OP0_SHIFT: u32 = 19;
|
||||
const SYSREG_OP0_MASK: u32 = 0b11u32 << 19;
|
||||
|
||||
@@ -82,7 +82,7 @@ pub mod aarch64;
|
||||
pub use aarch64::{
|
||||
arch_memory_regions, configure_system, configure_vcpu, fdt::DeviceInfoForFdt,
|
||||
get_host_cpu_phys_bits, initramfs_load_addr, layout, layout::CMDLINE_MAX_SIZE,
|
||||
layout::IRQ_BASE, uefi, EntryPoint,
|
||||
layout::IRQ_BASE, uefi, EntryPoint, _NSIG,
|
||||
};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
@@ -92,7 +92,7 @@ pub mod 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, CpuidFeatureEntry, EntryPoint,
|
||||
layout::CMDLINE_START, regs, CpuidFeatureEntry, EntryPoint, _NSIG,
|
||||
};
|
||||
|
||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||
|
||||
@@ -16,7 +16,7 @@ use crate::GuestMemoryMmap;
|
||||
use crate::InitramfsConfig;
|
||||
use crate::RegionType;
|
||||
use hypervisor::arch::x86::{CpuIdEntry, CPUID_FLAG_VALID_INDEX};
|
||||
use hypervisor::{HypervisorCpuError, HypervisorError};
|
||||
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,
|
||||
@@ -53,6 +53,8 @@ const KVM_FEATURE_ASYNC_PF_VMEXIT_BIT: u8 = 10;
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_FEATURE_STEAL_TIME_BIT: u8 = 5;
|
||||
|
||||
pub const _NSIG: i32 = 65;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
/// Specifies the entry point address where the guest must start
|
||||
/// executing code, as well as which of the supported boot protocols
|
||||
@@ -208,7 +210,6 @@ impl From<Error> for super::Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CpuidReg {
|
||||
EAX,
|
||||
@@ -774,6 +775,13 @@ pub fn configure_vcpu(
|
||||
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));
|
||||
|
||||
// Set ApicId in cpuid for each vcpu
|
||||
// SAFETY: get host cpuid when eax=1
|
||||
let mut cpu_ebx = unsafe { core::arch::x86_64::__cpuid(1) }.ebx;
|
||||
cpu_ebx &= 0xffffff;
|
||||
cpu_ebx |= (id as u32) << 24;
|
||||
CpuidPatch::set_cpuid_reg(&mut cpuid, 0x1, None, CpuidReg::EBX, cpu_ebx);
|
||||
|
||||
// The TSC frequency CPUID leaf should not be included when running with HyperV emulation
|
||||
if !kvm_hyperv {
|
||||
if let Some(tsc_khz) = vcpu.tsc_khz().map_err(Error::GetTscFrequency)? {
|
||||
@@ -826,47 +834,29 @@ pub fn configure_vcpu(
|
||||
/// These should be used to configure the GuestMemory structure for the platform.
|
||||
/// For x86_64 all addresses are valid from the start of the kernel except a
|
||||
/// carve out at the end of 32bit address space.
|
||||
pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
let reserved_memory_gap_start = layout::MEM_32BIT_RESERVED_START
|
||||
.checked_add(layout::MEM_32BIT_DEVICES_SIZE)
|
||||
.expect("32-bit reserved region is too large");
|
||||
|
||||
let requested_memory_size = GuestAddress(size);
|
||||
let mut regions = Vec::new();
|
||||
|
||||
// case1: guest memory fits before the gap
|
||||
if size <= layout::MEM_32BIT_RESERVED_START.raw_value() {
|
||||
regions.push((GuestAddress(0), size as usize, RegionType::Ram));
|
||||
// case2: guest memory extends beyond the gap
|
||||
} else {
|
||||
// push memory before the gap
|
||||
regions.push((
|
||||
pub fn arch_memory_regions() -> Vec<(GuestAddress, usize, RegionType)> {
|
||||
vec![
|
||||
// 0 GiB ~ 3GiB: memory before the gap
|
||||
(
|
||||
GuestAddress(0),
|
||||
layout::MEM_32BIT_RESERVED_START.raw_value() as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
regions.push((
|
||||
layout::RAM_64BIT_START,
|
||||
requested_memory_size.unchecked_offset_from(layout::MEM_32BIT_RESERVED_START) as usize,
|
||||
RegionType::Ram,
|
||||
));
|
||||
}
|
||||
|
||||
// Add the 32-bit device memory hole as a sub region.
|
||||
regions.push((
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||
RegionType::SubRegion,
|
||||
));
|
||||
|
||||
// Add the 32-bit reserved memory hole as a sub region.
|
||||
regions.push((
|
||||
reserved_memory_gap_start,
|
||||
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
||||
RegionType::Reserved,
|
||||
));
|
||||
|
||||
regions
|
||||
),
|
||||
// 4 GiB ~ inf: memory after the gap
|
||||
(layout::RAM_64BIT_START, usize::MAX, RegionType::Ram),
|
||||
// 3 GiB ~ 3712 MiB: 32-bit device memory hole
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START,
|
||||
layout::MEM_32BIT_DEVICES_SIZE as usize,
|
||||
RegionType::SubRegion,
|
||||
),
|
||||
// 3712 MiB ~ 3968 MiB: 32-bit reserved memory hole
|
||||
(
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_add(layout::MEM_32BIT_DEVICES_SIZE),
|
||||
(layout::MEM_32BIT_RESERVED_SIZE - layout::MEM_32BIT_DEVICES_SIZE) as usize,
|
||||
RegionType::Reserved,
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
/// Configures the system and should be called once per vm before starting vcpu threads.
|
||||
@@ -964,30 +954,102 @@ fn configure_pvh(
|
||||
// Create the memory map entries.
|
||||
add_memmap_entry(&mut memmap, 0, layout::EBDA_START.raw_value(), E820_RAM);
|
||||
|
||||
let mem_end = guest_mem.last_addr();
|
||||
// Merge continuous memory regions into one region.
|
||||
// Note: memory regions from "GuestMemory" are sorted and non-zero sized.
|
||||
let ram_regions = {
|
||||
let mut ram_regions = Vec::new();
|
||||
let mut current_start = guest_mem
|
||||
.iter()
|
||||
.next()
|
||||
.map(GuestMemoryRegion::start_addr)
|
||||
.expect("GuestMemory must have one memory region at least")
|
||||
.raw_value();
|
||||
let mut current_end = current_start;
|
||||
|
||||
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::HIGH_RAM_START.raw_value(),
|
||||
mem_end.unchecked_offset_from(layout::HIGH_RAM_START) + 1,
|
||||
E820_RAM,
|
||||
);
|
||||
} else {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::HIGH_RAM_START.raw_value(),
|
||||
layout::MEM_32BIT_RESERVED_START.unchecked_offset_from(layout::HIGH_RAM_START),
|
||||
E820_RAM,
|
||||
);
|
||||
if mem_end > layout::RAM_64BIT_START {
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
layout::RAM_64BIT_START.raw_value(),
|
||||
mem_end.unchecked_offset_from(layout::RAM_64BIT_START) + 1,
|
||||
E820_RAM,
|
||||
);
|
||||
for (start, size) in guest_mem
|
||||
.iter()
|
||||
.map(|m| (m.start_addr().raw_value(), m.len()))
|
||||
{
|
||||
if current_end == start {
|
||||
// This zone is continuous with the previous one.
|
||||
current_end += size;
|
||||
} else {
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
current_start = start;
|
||||
current_end = start + size;
|
||||
}
|
||||
}
|
||||
|
||||
ram_regions.push((current_start, current_end));
|
||||
|
||||
ram_regions
|
||||
};
|
||||
|
||||
if ram_regions.len() > 2 {
|
||||
error!(
|
||||
"There should be up to two non-continuous regions, devidided by the
|
||||
gap at the end of 32bit address space (e.g. between 3G and 4G)."
|
||||
);
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region before the gap
|
||||
{
|
||||
let (first_region_start, first_region_end) =
|
||||
ram_regions.first().ok_or(super::Error::MemmapTableSetup)?;
|
||||
let high_ram_start = layout::HIGH_RAM_START.raw_value();
|
||||
let mem_32bit_reserved_start = layout::MEM_32BIT_RESERVED_START.raw_value();
|
||||
|
||||
if !((first_region_start <= &high_ram_start)
|
||||
&& (first_region_end > &high_ram_start)
|
||||
&& (first_region_end <= &mem_32bit_reserved_start))
|
||||
{
|
||||
error!(
|
||||
"Unexpected first memory region layout: (start: 0x{:08x}, end: 0x{:08x}).
|
||||
high_ram_start: 0x{:08x}, mem_32bit_reserved_start: 0x{:08x}",
|
||||
first_region_start, first_region_end, high_ram_start, mem_32bit_reserved_start
|
||||
);
|
||||
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||
high_ram_start, first_region_end
|
||||
);
|
||||
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
high_ram_start,
|
||||
first_region_end - high_ram_start,
|
||||
E820_RAM,
|
||||
);
|
||||
}
|
||||
|
||||
// Create the memory map entry for memory region after the gap if any
|
||||
if let Some((second_region_start, second_region_end)) = ram_regions.get(1) {
|
||||
let ram_64bit_start = layout::RAM_64BIT_START.raw_value();
|
||||
|
||||
if second_region_start != &ram_64bit_start {
|
||||
error!(
|
||||
"Unexpected second memory region layout: start: 0x{:08x}, ram_64bit_start: 0x{:08x}",
|
||||
second_region_start, ram_64bit_start
|
||||
);
|
||||
|
||||
return Err(super::Error::MemmapTableSetup);
|
||||
}
|
||||
|
||||
info!(
|
||||
"create_memmap_entry, start: 0x{:08x}, end: 0x{:08x})",
|
||||
ram_64bit_start, second_region_end
|
||||
);
|
||||
add_memmap_entry(
|
||||
&mut memmap,
|
||||
ram_64bit_start,
|
||||
second_region_end - ram_64bit_start,
|
||||
E820_RAM,
|
||||
);
|
||||
}
|
||||
|
||||
add_memmap_entry(
|
||||
@@ -1077,7 +1139,7 @@ pub fn initramfs_load_addr(
|
||||
Ok(aligned_addr)
|
||||
}
|
||||
|
||||
pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
pub fn get_host_cpu_phys_bits(hypervisor: &Arc<dyn hypervisor::Hypervisor>) -> u8 {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x8000_0000);
|
||||
@@ -1086,9 +1148,7 @@ pub fn get_host_cpu_phys_bits() -> u8 {
|
||||
// Some physical address bits may become reserved when the feature is enabled.
|
||||
// See AMD64 Architecture Programmer's Manual Volume 2, Section 7.10.1
|
||||
let reduced = if leaf.eax >= 0x8000_001f
|
||||
&& leaf.ebx == 0x6874_7541 // Vendor ID: AuthenticAMD
|
||||
&& leaf.ecx == 0x444d_4163
|
||||
&& leaf.edx == 0x6974_6e65
|
||||
&& matches!(hypervisor.get_cpu_vendor(), CpuVendor::AMD)
|
||||
&& x86_64::__cpuid(0x8000_001f).eax & 0x1 != 0
|
||||
{
|
||||
(x86_64::__cpuid(0x8000_001f).ebx >> 6) & 0x3f
|
||||
@@ -1223,16 +1283,8 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn regions_lt_4gb() {
|
||||
let regions = arch_memory_regions(1 << 29);
|
||||
assert_eq!(3, regions.len());
|
||||
assert_eq!(GuestAddress(0), regions[0].0);
|
||||
assert_eq!(1usize << 29, regions[0].1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regions_gt_4gb() {
|
||||
let regions = arch_memory_regions((1 << 32) + 0x8000);
|
||||
fn regions_base_addr() {
|
||||
let regions = arch_memory_regions();
|
||||
assert_eq!(4, regions.len());
|
||||
assert_eq!(GuestAddress(0), regions[0].0);
|
||||
assert_eq!(GuestAddress(1 << 32), regions[1].0);
|
||||
@@ -1256,11 +1308,10 @@ mod tests {
|
||||
assert!(config_err.is_err());
|
||||
|
||||
// Now assigning some memory that falls before the 32bit memory hole.
|
||||
let mem_size = 128 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let arch_mem_regions = arch_memory_regions();
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.filter(|r| r.2 == RegionType::Ram && r.1 != usize::MAX)
|
||||
.map(|r| (r.0, r.1))
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
@@ -1278,48 +1329,18 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now assigning some memory that is equal to the start of the 32bit memory hole.
|
||||
let mem_size = 3328 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.map(|r| (r.0, r.1))
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
configure_system(
|
||||
&gm,
|
||||
GuestAddress(0),
|
||||
&None,
|
||||
no_vcpus,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
configure_system(
|
||||
&gm,
|
||||
GuestAddress(0),
|
||||
&None,
|
||||
no_vcpus,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Now assigning some memory that falls after the 32bit memory hole.
|
||||
let mem_size = 3330 << 20;
|
||||
let arch_mem_regions = arch_memory_regions(mem_size);
|
||||
let arch_mem_regions = arch_memory_regions();
|
||||
let ram_regions: Vec<(GuestAddress, usize)> = arch_mem_regions
|
||||
.iter()
|
||||
.filter(|r| r.2 == RegionType::Ram)
|
||||
.map(|r| (r.0, r.1))
|
||||
.map(|r| {
|
||||
if r.1 == usize::MAX {
|
||||
(r.0, 128 << 20)
|
||||
} else {
|
||||
(r.0, r.1)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let gm = GuestMemoryMmap::from_ranges(&ram_regions).unwrap();
|
||||
configure_system(
|
||||
|
||||
@@ -8,18 +8,18 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
io-uring = "0.5.12"
|
||||
io-uring = "0.5.13"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
qcow = { path = "../qcow" }
|
||||
smallvec = "1.10.0"
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
4
build.rs
4
build.rs
@@ -17,8 +17,8 @@ fn main() {
|
||||
}
|
||||
|
||||
// This println!() has a special behavior, as it will set the environment
|
||||
// variable BUILT_VERSION, so that it can be reused from the binary.
|
||||
// variable BUILD_VERSION, so that it can be reused from the binary.
|
||||
// Particularly, this is used from src/main.rs to display the exact
|
||||
// version.
|
||||
println!("cargo:rustc-env=BUILT_VERSION={version}");
|
||||
println!("cargo:rustc-env=BUILD_VERSION={version}");
|
||||
}
|
||||
|
||||
@@ -6,19 +6,19 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
acpi_tables = { git = "https://github.com/rust-vmm/acpi_tables", branch = "main" }
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
arch = { path = "../arch" }
|
||||
bitflags = "1.3.2"
|
||||
bitflags = "2.3.3"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
tpm = { path = "../tpm" }
|
||||
versionize = "0.1.9"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//
|
||||
|
||||
use super::AcpiNotificationFlags;
|
||||
use acpi_tables::{aml, aml::Aml};
|
||||
use acpi_tables::{aml, Aml, AmlSink};
|
||||
use std::sync::{Arc, Barrier};
|
||||
use std::time::Instant;
|
||||
use vm_device::interrupt::InterruptSourceGroup;
|
||||
@@ -103,11 +103,11 @@ impl BusDevice for AcpiGedDevice {
|
||||
}
|
||||
|
||||
impl Aml for AcpiGedDevice {
|
||||
fn append_aml_bytes(&self, bytes: &mut Vec<u8>) {
|
||||
fn to_aml_bytes(&self, sink: &mut dyn AmlSink) {
|
||||
aml::Device::new(
|
||||
"_SB_.GEC_".into(),
|
||||
vec![
|
||||
&aml::Name::new("_HID".into(), &aml::EisaName::new("PNP0A06")),
|
||||
&aml::Name::new("_HID".into(), &aml::EISAName::new("PNP0A06")),
|
||||
&aml::Name::new("_UID".into(), &"Generic Event Controller"),
|
||||
&aml::Name::new(
|
||||
"_CRS".into(),
|
||||
@@ -116,17 +116,19 @@ impl Aml for AcpiGedDevice {
|
||||
true,
|
||||
self.address.0,
|
||||
self.address.0 + GED_DEVICE_ACPI_SIZE as u64 - 1,
|
||||
None,
|
||||
)]),
|
||||
),
|
||||
&aml::OpRegion::new(
|
||||
"GDST".into(),
|
||||
aml::OpRegionSpace::SystemMemory,
|
||||
self.address.0 as usize,
|
||||
GED_DEVICE_ACPI_SIZE,
|
||||
&(self.address.0 as usize),
|
||||
&GED_DEVICE_ACPI_SIZE,
|
||||
),
|
||||
&aml::Field::new(
|
||||
"GDST".into(),
|
||||
aml::FieldAccessType::Byte,
|
||||
aml::FieldLockRule::NoLock,
|
||||
aml::FieldUpdateRule::WriteAsZeroes,
|
||||
vec![aml::FieldEntry::Named(*b"GDAT", 8)],
|
||||
),
|
||||
@@ -163,7 +165,7 @@ impl Aml for AcpiGedDevice {
|
||||
),
|
||||
],
|
||||
)
|
||||
.append_aml_bytes(bytes);
|
||||
.to_aml_bytes(sink);
|
||||
aml::Device::new(
|
||||
"_SB_.GED_".into(),
|
||||
vec![
|
||||
@@ -187,7 +189,7 @@ impl Aml for AcpiGedDevice {
|
||||
),
|
||||
],
|
||||
)
|
||||
.append_aml_bytes(bytes)
|
||||
.to_aml_bytes(sink)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
219
docs/api.md
219
docs/api.md
@@ -1,18 +1,21 @@
|
||||
- [Cloud Hypervisor API](#cloud-hypervisor-api)
|
||||
- [External API](#external-api)
|
||||
- [REST API](#rest-api)
|
||||
- [Location and availability](#location-and-availability)
|
||||
- [Endpoints](#endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [REST API Location and availability](#rest-api-location-and-availability)
|
||||
- [REST API Endpoints](#rest-api-endpoints)
|
||||
- [Virtual Machine Manager (VMM) Actions](#virtual-machine-manager-vmm-actions)
|
||||
- [Virtual Machine (VM) Actions](#virtual-machine-vm-actions)
|
||||
- [REST API Examples](#rest-api-examples)
|
||||
- [Create a Virtual Machine](#create-a-virtual-machine)
|
||||
- [Boot a Virtual Machine](#boot-a-virtual-machine)
|
||||
- [Dump a Virtual Machine Information](#dump-a-virtual-machine-information)
|
||||
- [Reboot a Virtual Machine](#reboot-a-virtual-machine)
|
||||
- [Shut a Virtual Machine Down](#shut-a-virtual-machine-down)
|
||||
- [D-Bus API](#d-bus-api)
|
||||
- [D-Bus API Location and availability](#d-bus-api-location-and-availability)
|
||||
- [D-Bus API Interface](#d-bus-api-interface)
|
||||
- [Command Line Interface](#command-line-interface)
|
||||
- [REST API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [REST API, D-Bus API and CLI Architectural Relationship](#rest-api-and-cli-architectural-relationship)
|
||||
- [Internal API](#internal-api)
|
||||
- [Goals and Design](#goals-and-design)
|
||||
- [End to End Example](#end-to-end-example)
|
||||
@@ -21,9 +24,11 @@
|
||||
|
||||
The Cloud Hypervisor API is made of 2 distinct interfaces:
|
||||
|
||||
1. **The external API**. This is the user facing API. Users and operators can
|
||||
control and manage Cloud Hypervisor through either a REST API or a Command
|
||||
Line Interface (CLI).
|
||||
1. **The External API** This is the user facing API. Users and operators
|
||||
can control and manage the Cloud Hypervisor through various options
|
||||
including a REST API, a Command Line Interface (CLI) or a D-Bus based API,
|
||||
which is not compiled into Cloud Hypervisor by default.
|
||||
|
||||
1. **The internal API**, based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/)
|
||||
module. This API is used internally by the Cloud Hypervisor threads to
|
||||
communicate between each others.
|
||||
@@ -40,10 +45,10 @@ API triggers VM and VMM specific actions, and as such it is designed as a
|
||||
collection of RPC-style, static methods.
|
||||
|
||||
The API is [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
|
||||
compliant. Please consult the [Cloud Hypervisor API](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
document for more details about the API payloads and responses.
|
||||
compliant. Please consult the [Cloud Hypervisor OpenAPI Document](https://raw.githubusercontent.com/cloud-hypervisor/cloud-hypervisor/master/vmm/src/api/openapi/cloud-hypervisor.yaml)
|
||||
for more details about the API payloads and responses.
|
||||
|
||||
### Location and availability
|
||||
#### REST API Location and availability
|
||||
|
||||
The REST API is available as soon as the Cloud Hypervisor binary is started,
|
||||
through a local UNIX socket.
|
||||
@@ -65,48 +70,55 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
### Endpoints
|
||||
#### REST API Endpoints
|
||||
|
||||
The Cloud Hypervisor API exposes the following actions through its endpoints:
|
||||
|
||||
#### Virtual Machine Manager (VMM) Actions
|
||||
##### Virtual Machine Manager (VMM) Actions
|
||||
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ----------------------------------- | --------------- | ------------ | -------------------------- | ------------------ |
|
||||
| Check for the REST API availability | `/vmm.ping` | N/A | `/schemas/VmmPingResponse` | N/A |
|
||||
| Shut the VMM down | `/vmm.shutdown` | N/A | N/A | The VMM is running |
|
||||
|
||||
#### Virtual Machine (VM) Actions
|
||||
##### Virtual Machine (VM) Actions
|
||||
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ---------------------------------- | --------------------- | --------------------------- | ------------------------ | -------------------------------- |
|
||||
| Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet |
|
||||
| Delete the VM | `/vm.delete` | N/A | N/A | N/A |
|
||||
| Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted |
|
||||
| Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted |
|
||||
| Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted |
|
||||
| Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted |
|
||||
| Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted |
|
||||
| Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused |
|
||||
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
|
||||
| Perform a coredump of the VM | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
|
||||
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
|
||||
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
|
||||
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
|
||||
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
|
||||
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
|
||||
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
|
||||
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
|
||||
| Action | Endpoint | Request Body | Response Body | Prerequisites |
|
||||
| ---------------------------------- | ----------------------- | ------------------------------- | ------------------------ | ------------------------------------------------------ |
|
||||
| Create the VM | `/vm.create` | `/schemas/VmConfig` | N/A | The VM is not created yet |
|
||||
| Delete the VM | `/vm.delete` | N/A | N/A | N/A |
|
||||
| Boot the VM | `/vm.boot` | N/A | N/A | The VM is created but not booted |
|
||||
| Shut the VM down | `/vm.shutdown` | N/A | N/A | The VM is booted |
|
||||
| Reboot the VM | `/vm.reboot` | N/A | N/A | The VM is booted |
|
||||
| Trigger power button of the VM | `/vm.power-button` | N/A | N/A | The VM is booted |
|
||||
| Pause the VM | `/vm.pause` | N/A | N/A | The VM is booted |
|
||||
| Resume the VM | `/vm.resume` | N/A | N/A | The VM is paused |
|
||||
| Task a snapshot of the VM | `/vm.snapshot` | `/schemas/VmSnapshotConfig` | N/A | The VM is paused |
|
||||
| Perform a coredump of the VM* | `/vm.coredump` | `/schemas/VmCoredumpData` | N/A | The VM is paused |
|
||||
| Restore the VM from a snapshot | `/vm.restore` | `/schemas/RestoreConfig` | N/A | The VM is created but not booted |
|
||||
| Add/remove CPUs to/from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
|
||||
| Add/remove memory from the VM | `/vm.resize` | `/schemas/VmResize` | N/A | The VM is booted |
|
||||
| Add/remove memory from a zone | `/vm.resize-zone` | `/schemas/VmResizeZone` | N/A | The VM is booted |
|
||||
| Dump the VM information | `/vm.info` | N/A | `/schemas/VmInfo` | The VM is created |
|
||||
| Add VFIO PCI device to the VM | `/vm.add-device` | `/schemas/VmAddDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add disk device to the VM | `/vm.add-disk` | `/schemas/DiskConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add fs device to the VM | `/vm.add-fs` | `/schemas/FsConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add pmem device to the VM | `/vm.add-pmem` | `/schemas/PmemConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add network device to the VM | `/vm.add-net` | `/schemas/NetConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add userspace PCI device to the VM | `/vm.add-user-device` | `/schemas/VmAddUserDevice` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add vdpa device to the VM | `/vm.add-vdpa` | `/schemas/VdpaConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Add vsock device to the VM | `/vm.add-vsock` | `/schemas/VsockConfig` | `/schemas/PciDeviceInfo` | The VM is booted |
|
||||
| Remove device from the VM | `/vm.remove-device` | `/schemas/VmRemoveDevice` | N/A | The VM is booted |
|
||||
| Dump the VM counters | `/vm.counters` | N/A | `/schemas/VmCounters` | The VM is booted |
|
||||
| Prepare to receive a migration | `/vm.receive-migration` | `/schemas/ReceiveMigrationData` | N/A | N/A |
|
||||
| Start to send migration to target | `/vm.send-migration` | `/schemas/SendMigrationData` | N/A | The VM is booted and (shared mem or hugepages enabled) |
|
||||
|
||||
### REST API Examples
|
||||
* The `vmcoredump` action is available exclusively for the `x86_64`
|
||||
architecture and can be executed only when the `guest_debug` feature is
|
||||
enabled. Without this feature, the corresponding [REST API](#rest-api) or
|
||||
[D-Bus API](#d-bus-api) endpoints are not available.
|
||||
|
||||
#### REST API Examples
|
||||
|
||||
For the following set of examples, we assume Cloud Hypervisor is started with
|
||||
the REST API available at `/tmp/cloud-hypervisor.sock`:
|
||||
@@ -122,7 +134,7 @@ Cloud Hypervisor Guest
|
||||
Disk(s): None
|
||||
```
|
||||
|
||||
#### Create a Virtual Machine
|
||||
##### Create a Virtual Machine
|
||||
|
||||
We want to create a virtual machine with the following characteristics:
|
||||
|
||||
@@ -150,7 +162,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
}'
|
||||
```
|
||||
|
||||
#### Boot a Virtual Machine
|
||||
##### Boot a Virtual Machine
|
||||
|
||||
Once the VM is created, we can boot it:
|
||||
|
||||
@@ -160,7 +172,7 @@ Once the VM is created, we can boot it:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.boot'
|
||||
```
|
||||
|
||||
#### Dump a Virtual Machine Information
|
||||
##### Dump a Virtual Machine Information
|
||||
|
||||
We can fetch information about any VM, as soon as it's created:
|
||||
|
||||
@@ -172,7 +184,7 @@ curl --unix-socket /tmp/cloud-hypervisor.sock -i \
|
||||
-H 'Accept: application/json'
|
||||
```
|
||||
|
||||
#### Reboot a Virtual Machine
|
||||
##### Reboot a Virtual Machine
|
||||
|
||||
We can reboot a VM that's already booted:
|
||||
|
||||
@@ -182,7 +194,7 @@ We can reboot a VM that's already booted:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.reboot'
|
||||
```
|
||||
|
||||
#### Shut a Virtual Machine Down
|
||||
##### Shut a Virtual Machine Down
|
||||
|
||||
Once booted, we can shut a VM down from the REST API:
|
||||
|
||||
@@ -192,6 +204,50 @@ Once booted, we can shut a VM down from the REST API:
|
||||
curl --unix-socket /tmp/cloud-hypervisor.sock -i -X PUT 'http://localhost/api/v1/vm.shutdown'
|
||||
```
|
||||
|
||||
### D-Bus API
|
||||
|
||||
Cloud Hypervisor offers a D-Bus API as an alternative to its REST API. As of
|
||||
writing this document, the D-Bus API mirrors the functionality of the REST
|
||||
API and shares the same set of endpoints, meaning that it supports every call
|
||||
that is supported by the REST API and can be a drop-in replacement since it
|
||||
also consumes/produces JSON.
|
||||
|
||||
#### D-Bus API Location and availability
|
||||
|
||||
This feature is not compiled into Cloud Hypervisor by default. Users who
|
||||
wish to use the D-Bus API, must explicitly enable it with the `dbus_api`
|
||||
feature flag when compiling Cloud Hypervisor.
|
||||
|
||||
```sh
|
||||
$ ./scripts/dev_cli.sh build --release --libc musl -- --features dbus_api
|
||||
```
|
||||
|
||||
Once this feature is enabled, it can be configured with the following
|
||||
CLI options:
|
||||
|
||||
```
|
||||
--dbus-service-name
|
||||
well known name of the service
|
||||
--dbus-object-path
|
||||
object path to serve the dbus interface
|
||||
--dbus-system-bus use the system bus instead of a session bus
|
||||
```
|
||||
|
||||
Example invocation:
|
||||
|
||||
```sh
|
||||
$ ./cloud-hypervisor --dbus-service-name "org.cloudhypervisor.DBusApi" \
|
||||
--dbus-object-path "/org/cloudhypervisor/DBusApi"
|
||||
```
|
||||
|
||||
This will start serving a service with the name `org.cloudhypervisor.DBusApi1`
|
||||
which in turn can be used to control and manage Cloud Hypervisor.
|
||||
|
||||
#### D-Bus API Interface
|
||||
|
||||
Please refer to the [REST API](#rest-api) documentation. As previously
|
||||
mentioned, the D-Bus API currently mirrors the behaviour of the REST API.
|
||||
|
||||
### Command Line Interface
|
||||
|
||||
The Cloud Hypervisor Command Line Interface (CLI) can only be used for launching
|
||||
@@ -199,33 +255,41 @@ the Cloud Hypervisor binary, i.e. it can not be used for controlling the VMM or
|
||||
the launched VM once they're up and running.
|
||||
|
||||
If you want to inspect the VMM, or control the VM after launching Cloud
|
||||
Hypervisor from the CLI, you must use the [REST API](#rest-api).
|
||||
Hypervisor from the CLI, you must use either the [REST API](#rest-api)
|
||||
or the [D-Bus API](#d-bus-api).
|
||||
|
||||
From the CLI, one can either:
|
||||
From the CLI, one can:
|
||||
|
||||
1. Create and boot a complete virtual machine by using the CLI options to build
|
||||
the VM config. Run `cloud-hypervisor --help` for a complete list of CLI
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, the
|
||||
[REST API](#rest-api) is available for controlling and managing the VM.
|
||||
1. Start the [REST API](#rest-api) server only, by not passing any VM
|
||||
configuration options. The VM can then be asynchronously created and booted
|
||||
by sending HTTP commands to the [REST API](#rest-api). Check the
|
||||
[REST API examples](#rest-api-examples) section for more details.
|
||||
options. As soon as the `cloud-hypervisor` binary is launched, contrary
|
||||
to the [D-Bus API](#d-bus-api), the [REST API](#rest-api) is available
|
||||
for controlling and managing the VM. The [D-Bus API](#d-bus-api) doesn't start
|
||||
automatically and needs to be explicitly configured in order to be run.
|
||||
1. Start either the REST API, D-Bus API or both simultaneously without passing
|
||||
any VM configuration options. The VM can then be asynchronously created and
|
||||
booted by calling API methods of choice. It should be noted that one external
|
||||
API does not exclude another; it is possible to have both the REST and D-Bus
|
||||
APIs running simultaneously.
|
||||
|
||||
### REST API and CLI Architectural Relationship
|
||||
### REST API, D-Bus API and CLI Architectural Relationship
|
||||
|
||||
The REST API and the CLI both rely on a common, [internal API](#internal-api).
|
||||
The REST API, D-Bus API and the CLI all rely on a common, [internal API](#internal-api).
|
||||
|
||||
The CLI options are parsed by the
|
||||
[argh crate](https://docs.rs/argh/latest/argh/) and then translated into
|
||||
[internal API](#internal-api) commands.
|
||||
|
||||
The REST API is processed by an HTTP thread using the
|
||||
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
|
||||
[Firecracker's `micro_http`](https://github.com/firecracker-microvm/micro-http)
|
||||
crate. As with the CLI, the HTTP requests eventually get translated into
|
||||
[internal API](#internal-api) commands.
|
||||
|
||||
As a summary, the REST API and the CLI are essentially frontends for the
|
||||
The D-Bus API is implemented using the [zbus](https://github.com/dbus2/zbus)
|
||||
crate and runs in its own thread. Whenever it needs to call the [internal API](#internal-api),
|
||||
the [blocking](https://github.com/smol-rs/blocking) crate is used perform the call in zbus' async context.
|
||||
|
||||
As a summary, the REST API, the D-Bus API and the CLI are essentially frontends for the
|
||||
[internal API](#internal-api):
|
||||
|
||||
```
|
||||
@@ -236,11 +300,11 @@ As a summary, the REST API and the CLI are essentially frontends for the
|
||||
| +------------------+ |
|
||||
| | +------------------------+
|
||||
| | | |
|
||||
+------------+ | | | |
|
||||
| | | | | +--------------+ |
|
||||
| User +---------+ +------> | Internal API | |
|
||||
| | | | | +--------------+ |
|
||||
+------------+ | | | |
|
||||
+------------+ | +----------+ | | |
|
||||
| | | D-Bus API | | | | +--------------+ |
|
||||
| User +---------+----------->+ zbus +--------------+------> | Internal API | |
|
||||
| | | | | | | +--------------+ |
|
||||
+------------+ | +----------+ | | |
|
||||
| | | |
|
||||
| | +------------------------+
|
||||
| +----------+ | VMM
|
||||
@@ -255,22 +319,23 @@ As a summary, the REST API and the CLI are essentially frontends for the
|
||||
## Internal API
|
||||
|
||||
The Cloud Hypervisor internal API, as its name suggests, is used internally
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, control loop, etc) to
|
||||
send commands and responses to each others.
|
||||
by the different Cloud Hypervisor threads (VMM, HTTP, D-Bus, control loop,
|
||||
etc) to send commands and responses to each others.
|
||||
|
||||
It is based on [rust's Multi-Producer, Single-Consumer (MPSC)](https://doc.rust-lang.org/std/sync/mpsc/),
|
||||
and the single consumer (a.k.a. the API receiver) is the Cloud Hypervisor
|
||||
control loop.
|
||||
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api) and the
|
||||
main thread that initially parses the [CLI](#command-line-interface).
|
||||
API producers are the HTTP thread handling the [REST API](#rest-api), the
|
||||
D-Bus thread handling the [D-Bus API](#d-bus-api) and the main thread that
|
||||
initially parses the [CLI](#command-line-interface).
|
||||
|
||||
### Goals and Design
|
||||
|
||||
The internal API is designed for controlling, managing and inspecting a Cloud
|
||||
Hypervisor VMM and its guest. It is a backend for handling external, user
|
||||
visible requests through either the [REST API](#rest-api) or the
|
||||
[CLI](#command-line-interface) interfaces.
|
||||
visible requests through the [REST API](#rest-api), the [D-Bus API](#d-bus-api)
|
||||
or the [CLI](#command-line-interface) interfaces.
|
||||
|
||||
The API follows a command-response scheme that closely maps the [REST API](#rest-api).
|
||||
Any command must be replied to with a response.
|
||||
@@ -379,5 +444,5 @@ APIs work together, let's look at a complete VM creation flow, from the
|
||||
```
|
||||
1. The Cloud Hypervisor HTTP thread sends the formed HTTP response back to the
|
||||
user. This is abstracted by the
|
||||
[micro_http](https://github.com/firecracker-microvm/firecracker/tree/master/src/micro_http)
|
||||
[micro_http](https://github.com/firecracker-microvm/micro-http)
|
||||
crate.
|
||||
|
||||
@@ -225,7 +225,7 @@ Number Start End Size File system Name Flags
|
||||
|
||||
### Create a macvtap interface
|
||||
|
||||
Rely on the following [documentation](docs/macvtap-bridge.md) to set up a
|
||||
Rely on the following [documentation](macvtap-bridge.md) to set up a
|
||||
macvtap interface to provide your VM with proper connectivity.
|
||||
|
||||
### Boot the image
|
||||
|
||||
@@ -266,11 +266,8 @@ _Example_
|
||||
|
||||
### `file`
|
||||
|
||||
Path to the file backing the memory zone. This can be either a file or a
|
||||
directory. In case of a file, it will be opened and used as the backing file
|
||||
for the `mmap(2)` operation. In case of a directory, a temporary file with no
|
||||
hard link on the filesystem will be created. This file will be used as the
|
||||
backing file for the `mmap(2)` operation.
|
||||
Path to the file backing the memory zone. The file will be opened and used as
|
||||
the backing file for the `mmap(2)` operation.
|
||||
|
||||
This option can be particularly useful when trying to back a part of the guest
|
||||
RAM with a well known file. In the context of the snapshot/restore feature, and
|
||||
|
||||
@@ -6,5 +6,5 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.139"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.93"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
|
||||
230
fuzz/Cargo.lock
generated
230
fuzz/Cargo.lock
generated
@@ -5,16 +5,16 @@ version = 3
|
||||
[[package]]
|
||||
name = "acpi_tables"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#4fd38dd5f746730ec5ae848dafcf8c2f50a13fc3"
|
||||
source = "git+https://github.com/rust-vmm/acpi_tables?branch=main#05a609136387cc1cc9b499cee4320020325c263f"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.69"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
@@ -25,9 +25,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.2.3"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e90af4de65aa7b293ef2d09daff88501eb254f58edde2e1ac02c82d873eadad"
|
||||
checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
@@ -76,7 +76,7 @@ dependencies = [
|
||||
"argh_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -100,6 +100,12 @@ version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded"
|
||||
|
||||
[[package]]
|
||||
name = "block_util"
|
||||
version = "0.1.0"
|
||||
@@ -113,7 +119,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhdx",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -143,7 +149,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cloud-hypervisor"
|
||||
version = "29.0.0"
|
||||
version = "32.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
@@ -208,9 +214,9 @@ checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.14.3"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0808e1bd8671fb44a113a14e13497557533369847788fa2ae912b6ebfce9fa8"
|
||||
checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
@@ -218,27 +224,27 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.14.3"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "001d80444f28e193f30c2f293455da62dcf9a6b29918a4253152ae2b1de592cb"
|
||||
checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.14.3"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b36230598a2d5de7ec1c6f51f72d8a99a9208daff41de2084d06e3fd3ea56685"
|
||||
checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -248,7 +254,7 @@ dependencies = [
|
||||
"acpi_tables",
|
||||
"anyhow",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.3.2",
|
||||
"byteorder",
|
||||
"hypervisor",
|
||||
"libc",
|
||||
@@ -269,7 +275,7 @@ version = "4.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20df693c700404f7e19d4d6fae6b15215d2913c27955d2b9d6f2c0f537511cd0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -296,9 +302,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
@@ -326,9 +332,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iced-x86"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd04b950d75b3498320253b17fb92745b2cc79ead8814aede2f7c1bab858bec"
|
||||
checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
@@ -345,21 +351,21 @@ version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd1e1a01cfb924fd8c5c43b6827965db394f5a3a16c599ce03452266e1cf984c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.5"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
||||
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b"
|
||||
checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
@@ -393,9 +399,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.139"
|
||||
version = "0.2.147"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
@@ -410,21 +416,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-loader"
|
||||
version = "0.8.1"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9259ddbfbb52cc918f6bbc60390004ddd0228cf1d85f402009ff2b3d95de83f"
|
||||
checksum = "8d3adb7b28e189741eca3b1a4a27de0bf15e0907c9d4b0c74bd2d7d84ef72e08"
|
||||
dependencies = [
|
||||
"vm-memory",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
||||
|
||||
[[package]]
|
||||
name = "micro_http"
|
||||
@@ -456,7 +459,7 @@ dependencies = [
|
||||
"thiserror",
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-memory",
|
||||
"vm-virtio",
|
||||
@@ -465,9 +468,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "option_parser"
|
||||
@@ -498,9 +501,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
version = "1.0.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -518,9 +521,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.23"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -536,13 +539,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "remain"
|
||||
version = "0.2.6"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5704e2cda92fd54202f05430725317ba0ea7d0c96b246ca0a92e45177127ba3b"
|
||||
checksum = "e13cca257d068dd3a390d04b2c3009a3fad2ee5048dfa8f239d048372810470c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -556,9 +559,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.12"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "seccompiler"
|
||||
@@ -571,35 +574,35 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.16"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a"
|
||||
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.152"
|
||||
version = "1.0.164"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.93"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||
checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@@ -608,9 +611,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "2.2.0"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c"
|
||||
checksum = "9f02d8aa6e3c385bf084924f660ce2a3a6bd333ba55b35e8590b321f35d88513"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_with_macros",
|
||||
@@ -618,14 +621,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "2.2.0"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1966009f3c05f095697c537312f5415d1e3ed31ce0a56942bac4c771c5c335e"
|
||||
checksum = "edc7d5d3932fb12ce722ee5e64dd38c504efba37567f0c402f6ca728c3b8b070"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -665,9 +668,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.108"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d56e159d99e6c2b93995d171050271edb50ecc5288fbc7cc17de8fdce4e58c14"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -676,22 +690,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
||||
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.38"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.15",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -720,24 +734,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.3.0"
|
||||
version = "1.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1674845326ee10d37ca60470760d4288a6f80f304007d92e5c53bab78c9cfd79"
|
||||
checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "versionize"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6e2495726cf917e7ba7ec8bf0f0fceab543dd38d0a4195ed6bef331e38a290f"
|
||||
checksum = "dca4b7062e7e6d685901e815c35f9671e059de97c1c0905eeff8592f3fff442f"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crc64",
|
||||
@@ -745,7 +759,7 @@ dependencies = [
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
"versionize_derive",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -753,17 +767,17 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "versionize_derive"
|
||||
version = "0.1.4"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#ae35ef7a3ddabd3371ab8ac0193a383aff6e4b1b"
|
||||
source = "git+https://github.com/cloud-hypervisor/versionize_derive?branch=ch#e502b1d4aabab342386f0c53780d49f21a6a1df6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vfio-bindings"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
dependencies = [
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -771,7 +785,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio-ioctls"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#43439e056ddfa84a4f7906ee7f2f58be70505c08"
|
||||
source = "git+https://github.com/rust-vmm/vfio?branch=main#89f8e77dd1a2829197ecde65b686bafcc8a1def4"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"kvm-bindings",
|
||||
@@ -787,9 +801,9 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vfio_user"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#afbbd5722885e961ce12baea12efe01d52ce14b0"
|
||||
source = "git+https://github.com/rust-vmm/vfio-user?branch=main#eef6bec4d421f08ed1688fe67c5ea33aabbf5069"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"log",
|
||||
"serde",
|
||||
@@ -816,22 +830,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "vhost"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9b791c5b0717a0558888a4cf7240cea836f39a99cb342e12ce633dcaa078072"
|
||||
checksum = "84f81f436bca4541f4d33172e1202882c9d437db34ed17fc6d84c8ff2bde21f5"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ff512178285488516ed85f15b5d0113a7cdb89e9e8a760b269ae4f02b84bd6b"
|
||||
|
||||
[[package]]
|
||||
name = "virtio-bindings"
|
||||
version = "0.2.0"
|
||||
@@ -863,7 +871,7 @@ dependencies = [
|
||||
"versionize",
|
||||
"versionize_derive",
|
||||
"vhost",
|
||||
"virtio-bindings 0.2.0",
|
||||
"virtio-bindings",
|
||||
"virtio-queue",
|
||||
"vm-allocator",
|
||||
"vm-device",
|
||||
@@ -875,12 +883,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "virtio-queue"
|
||||
version = "0.7.1"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ba81e2bcc21c0d2fc5e6683e79367e26ad219197423a498df801d79d5ba77bd"
|
||||
checksum = "91aebb1df33db33cbf04d4c2445e4f78d0b0c8e65acfd16a4ee95ef63ca252f8"
|
||||
dependencies = [
|
||||
"log",
|
||||
"virtio-bindings 0.1.0",
|
||||
"virtio-bindings",
|
||||
"vm-memory",
|
||||
"vmm-sys-util",
|
||||
]
|
||||
@@ -914,9 +922,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#c5a99ab71b130435927
|
||||
|
||||
[[package]]
|
||||
name = "vm-memory"
|
||||
version = "0.10.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "688a70366615b45575a424d9c665561c1b5ab2224d494f706b6a6812911a827c"
|
||||
checksum = "9d6ea57fe00f9086c59eeeb68e102dd611686bc3c28520fa465996d4d4bdce07"
|
||||
dependencies = [
|
||||
"arc-swap",
|
||||
"libc",
|
||||
@@ -953,7 +961,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"arch",
|
||||
"bitflags",
|
||||
"bitflags 2.3.2",
|
||||
"block_util",
|
||||
"devices",
|
||||
"epoll",
|
||||
@@ -989,6 +997,7 @@ dependencies = [
|
||||
"vm-migration",
|
||||
"vm-virtio",
|
||||
"vmm-sys-util",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -997,7 +1006,7 @@ version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
@@ -1030,3 +1039,24 @@ name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
@@ -12,20 +12,20 @@ cargo-fuzz = true
|
||||
block_util = { path = "../block_util" }
|
||||
devices = { path = "../devices" }
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.138"
|
||||
libc = "0.2.147"
|
||||
libfuzzer-sys = "0.4.6"
|
||||
linux-loader = { version = "0.8.1", features = ["elf", "bzimage", "pe"] }
|
||||
linux-loader = { version = "0.9.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.17.1"
|
||||
once_cell = "1.18.0"
|
||||
qcow = { path = "../qcow" }
|
||||
seccompiler = "0.3.0"
|
||||
vhdx = { path = "../vhdx" }
|
||||
virtio-devices = { path = "../virtio-devices" }
|
||||
virtio-queue = "0.7.1"
|
||||
virtio-queue = "0.8.0"
|
||||
vmm = { path = "../vmm" }
|
||||
vmm-sys-util = "0.11.1"
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
|
||||
|
||||
@@ -6,28 +6,28 @@ edition = "2021"
|
||||
license = "Apache-2.0 OR BSD-3-Clause"
|
||||
|
||||
[features]
|
||||
kvm = ["kvm-ioctls", "kvm-bindings"]
|
||||
mshv = ["mshv-ioctls", "mshv-bindings"]
|
||||
kvm = ["kvm-ioctls", "kvm-bindings", "vfio-ioctls/kvm"]
|
||||
mshv = ["mshv-ioctls", "mshv-bindings", "vfio-ioctls/mshv"]
|
||||
tdx = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
kvm-ioctls = { version = "0.13.0", optional = true }
|
||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.6.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_with = { version = "2.1.0", default-features = false, features = ["macros"] }
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_with = { version = "3.0.0", default-features = false, features = ["macros"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vmm-sys-util = { version = "0.11.0", features = ["with-serde"] }
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
default-features = false
|
||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ pub const MTRR_MEM_TYPE_WB: u64 = 0x6;
|
||||
pub const NUM_IOAPIC_PINS: usize = 24;
|
||||
|
||||
// X86 Exceptions
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Exception {
|
||||
DE = 0, // Divide Error
|
||||
|
||||
@@ -21,6 +21,15 @@ use crate::MpState;
|
||||
use thiserror::Error;
|
||||
use vm_memory::GuestAddress;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub enum CpuVendor {
|
||||
#[default]
|
||||
Unknown,
|
||||
Intel,
|
||||
AMD,
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
///
|
||||
/// Enum for CPU error
|
||||
|
||||
@@ -9,10 +9,14 @@
|
||||
//
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::CpuIdEntry;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::cpu::CpuVendor;
|
||||
#[cfg(feature = "tdx")]
|
||||
use crate::kvm::TdxCapabilities;
|
||||
use crate::vm::Vm;
|
||||
use crate::HypervisorType;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::arch::x86_64;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -75,6 +79,11 @@ pub enum HypervisorError {
|
||||
///
|
||||
#[error("Failed to set partition property:{0}")]
|
||||
SetPartitionProperty(#[source] anyhow::Error),
|
||||
///
|
||||
/// Running on an unsupported CPU
|
||||
///
|
||||
#[error("Unsupported CPU:{0}")]
|
||||
UnsupportedCpu(#[source] anyhow::Error),
|
||||
}
|
||||
|
||||
///
|
||||
@@ -133,4 +142,30 @@ pub trait Hypervisor: Send + Sync {
|
||||
fn get_guest_debug_hw_bps(&self) -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Determine CPU vendor
|
||||
///
|
||||
fn get_cpu_vendor(&self) -> CpuVendor {
|
||||
// SAFETY: call cpuid with valid leaves
|
||||
unsafe {
|
||||
let leaf = x86_64::__cpuid(0x0);
|
||||
|
||||
if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 {
|
||||
// Vendor string GenuineIntel
|
||||
CpuVendor::Intel
|
||||
} else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65
|
||||
{
|
||||
// Vendor string AuthenticAMD
|
||||
CpuVendor::AMD
|
||||
} else {
|
||||
// Not known yet, the corresponding manufacturer manual should contain the
|
||||
// necesssary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String
|
||||
CpuVendor::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,7 +243,6 @@ impl KvmGicV3Its {
|
||||
}
|
||||
|
||||
/// Method to initialize the GIC device
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub fn new(vm: &dyn Vm, config: VgicConfig) -> Result<KvmGicV3Its> {
|
||||
// This is inside KVM module
|
||||
let vm = vm.as_any().downcast_ref::<KvmVm>().expect("Wrong VM type?");
|
||||
|
||||
@@ -335,16 +335,17 @@ impl KvmVm {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Implementation of Vm trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl vm::Vm for KvmVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -917,13 +918,16 @@ impl KvmHypervisor {
|
||||
}
|
||||
}
|
||||
/// Implementation of Hypervisor trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
///
|
||||
/// Returns the type of the hypervisor
|
||||
@@ -932,13 +936,15 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
HypervisorType::Kvm
|
||||
}
|
||||
/// Create a KVM vm object of a specific VM type and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// use hypervisor::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm_with_type(KvmVmType::LegacyVm).unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// use hypervisor::kvm::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm_with_type(0).unwrap();
|
||||
/// ```
|
||||
fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
let fd: VmFd;
|
||||
loop {
|
||||
@@ -992,13 +998,15 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
}
|
||||
|
||||
/// Create a KVM vm object and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// use hypervisor::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// use hypervisor::kvm::KvmVm;
|
||||
/// let hypervisor = KvmHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap();
|
||||
/// ```
|
||||
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
#[allow(unused_mut)]
|
||||
let mut vm_type: u64 = 0; // Create with default platform type
|
||||
@@ -1076,6 +1084,11 @@ impl hypervisor::Hypervisor for KvmHypervisor {
|
||||
self.kvm.get_guest_debug_hw_bps() as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32 {
|
||||
self.kvm.get_max_vcpus().min(u32::MAX as usize) as u32
|
||||
}
|
||||
}
|
||||
/// Vcpu struct for KVM
|
||||
pub struct KvmVcpu {
|
||||
@@ -1087,15 +1100,17 @@ pub struct KvmVcpu {
|
||||
hyperv_synic: AtomicBool,
|
||||
}
|
||||
/// Implementation of Vcpu trait for KVM
|
||||
/// Example:
|
||||
/// #[cfg(feature = "kvm")]
|
||||
/// extern crate hypervisor
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(kvm);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
/// vcpu.get/set().unwrap()
|
||||
///
|
||||
/// ```
|
||||
impl cpu::Vcpu for KvmVcpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -1797,11 +1812,10 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hv = Arc::new(kvm);
|
||||
/// let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.enable_split_irq().unwrap();
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
@@ -1969,11 +1983,10 @@ impl cpu::Vcpu for KvmVcpu {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::KvmHypervisor;
|
||||
/// # use hypervisor::kvm::KvmHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
|
||||
/// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
|
||||
/// let kvm = KvmHypervisor::new().unwrap();
|
||||
/// let hv = Arc::new(kvm);
|
||||
/// let vm = hv.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.enable_split_irq().unwrap();
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
|
||||
@@ -48,9 +48,11 @@ mod cpu;
|
||||
/// Device related module
|
||||
mod device;
|
||||
|
||||
pub use crate::hypervisor::{Hypervisor, HypervisorError};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use cpu::CpuVendor;
|
||||
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
||||
pub use device::HypervisorDeviceError;
|
||||
pub use hypervisor::{Hypervisor, HypervisorError};
|
||||
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
|
||||
pub use kvm::{aarch64, GicState};
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -195,13 +195,16 @@ impl MshvHypervisor {
|
||||
}
|
||||
}
|
||||
/// Implementation of Hypervisor trait for Mshv
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// extern crate hypervisor
|
||||
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
///
|
||||
/// Returns the type of the hypervisor
|
||||
@@ -210,13 +213,16 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
HypervisorType::Mshv
|
||||
}
|
||||
/// Create a mshv vm object and return the object as Vm trait object
|
||||
/// Example
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::MshvHypervisor;
|
||||
/// use hypervisor::MshvVm;
|
||||
/// let hypervisor = MshvHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// use hypervisor::mshv::MshvVm;
|
||||
/// let hypervisor = MshvHypervisor::new().unwrap();
|
||||
/// let vm = hypervisor.create_vm().unwrap();
|
||||
/// ```
|
||||
fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
|
||||
let fd: VmFd;
|
||||
loop {
|
||||
@@ -273,6 +279,13 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
/// Get maximum number of vCPUs
|
||||
fn get_max_vcpus(&self) -> u32 {
|
||||
// TODO: Using HV_MAXIMUM_PROCESSORS would be better
|
||||
// but the ioctl API is limited to u8
|
||||
256
|
||||
}
|
||||
}
|
||||
|
||||
/// Vcpu struct for Microsoft Hypervisor
|
||||
@@ -285,15 +298,17 @@ pub struct MshvVcpu {
|
||||
}
|
||||
|
||||
/// Implementation of Vcpu trait for Microsoft Hypervisor
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// extern crate hypervisor
|
||||
/// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0).unwrap();
|
||||
/// vcpu.get/set().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// let vcpu = vm.create_vcpu(0, None).unwrap();
|
||||
/// ```
|
||||
impl cpu::Vcpu for MshvVcpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -446,10 +461,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
@@ -495,10 +510,10 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
/* Advance RIP and update RAX */
|
||||
let arr_reg_name_value = [
|
||||
(
|
||||
hv_x64_register_name_HV_X64_REGISTER_RIP,
|
||||
hv_register_name_HV_X64_REGISTER_RIP,
|
||||
info.header.rip + insn_len,
|
||||
),
|
||||
(hv_x64_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
(hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
|
||||
];
|
||||
set_registers_64!(self.fd, arr_reg_name_value)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
|
||||
@@ -568,8 +583,14 @@ impl cpu::Vcpu for MshvVcpu {
|
||||
///
|
||||
/// X86 specific call to setup the CPUID registers.
|
||||
///
|
||||
fn set_cpuid2(&self, _cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
|
||||
Ok(())
|
||||
fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
|
||||
let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect();
|
||||
let mshv_cpuid = <CpuId>::from_entries(&cpuid)
|
||||
.map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
|
||||
|
||||
self.fd
|
||||
.register_intercept_result_cpuid(&mshv_cpuid)
|
||||
.map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
|
||||
}
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
@@ -917,15 +938,17 @@ impl MshvVm {
|
||||
|
||||
///
|
||||
/// Implementation of Vm trait for Mshv
|
||||
/// Example:
|
||||
/// #[cfg(feature = "mshv")]
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::MshvHypervisor;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// vm.set/get().unwrap()
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # extern crate hypervisor;
|
||||
/// # use hypervisor::mshv::MshvHypervisor;
|
||||
/// # use std::sync::Arc;
|
||||
/// let mshv = MshvHypervisor::new().unwrap();
|
||||
/// let hypervisor = Arc::new(mshv);
|
||||
/// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
|
||||
/// ```
|
||||
impl vm::Vm for MshvVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
impl<T> __IncompleteArrayField<T> {
|
||||
#[inline]
|
||||
pub const fn new() -> Self {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
#![allow(clippy::all)]
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
@@ -28,10 +27,12 @@ pub mod inn;
|
||||
// generated with bindgen /usr/include/linux/sockios.h --no-unstable-rust
|
||||
// --constified-enum '*' --with-derive-default
|
||||
pub mod sockios;
|
||||
pub use if_tun::*;
|
||||
pub use iff::*;
|
||||
pub use inn::*;
|
||||
pub use sockios::*;
|
||||
pub use if_tun::{
|
||||
sock_fprog, IFF_MULTI_QUEUE, IFF_NO_PI, IFF_TAP, IFF_VNET_HDR, TUN_F_CSUM, TUN_F_TSO4,
|
||||
TUN_F_TSO6, TUN_F_TSO_ECN, TUN_F_UFO,
|
||||
};
|
||||
pub use iff::{ifreq, net_device_flags_IFF_UP, setsockopt, sockaddr, AF_INET};
|
||||
pub use inn::sockaddr_in;
|
||||
|
||||
pub const TUNTAP: ::std::os::raw::c_uint = 84;
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
serde = "1.0.151"
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
serde = "1.0.164"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -25,4 +25,4 @@ vmm-sys-util = "0.11.0"
|
||||
once_cell = "1.17.1"
|
||||
pnet = "0.33.0"
|
||||
pnet_datalink = "0.33.0"
|
||||
serde_json = "1.0.93"
|
||||
serde_json = "1.0.96"
|
||||
|
||||
@@ -10,7 +10,7 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
byteorder = "1.4.3"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
vfio-bindings = { git = "https://github.com/rust-vmm/vfio", branch = "main", features = ["fam-wrappers"] }
|
||||
@@ -20,11 +20,11 @@ vfio_user = { git = "https://github.com/rust-vmm/vfio-user", branch = "main" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
serde = { version = "1.0.151", features = ["derive"] }
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
|
||||
@@ -452,10 +452,9 @@ impl From<PciBarType> for PciBarRegionType {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<PciBarType> for PciBarRegionType {
|
||||
fn into(self) -> PciBarType {
|
||||
match self {
|
||||
impl From<PciBarRegionType> for PciBarType {
|
||||
fn from(val: PciBarRegionType) -> Self {
|
||||
match val {
|
||||
PciBarRegionType::IoRegion => PciBarType::Io,
|
||||
PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
|
||||
PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
|
||||
@@ -469,10 +468,9 @@ pub enum PciBarPrefetchable {
|
||||
Prefetchable = 0x08,
|
||||
}
|
||||
|
||||
#[allow(clippy::from_over_into)]
|
||||
impl Into<bool> for PciBarPrefetchable {
|
||||
fn into(self) -> bool {
|
||||
match self {
|
||||
impl From<PciBarPrefetchable> for bool {
|
||||
fn from(val: PciBarPrefetchable) -> Self {
|
||||
match val {
|
||||
PciBarPrefetchable::NotPrefetchable => false,
|
||||
PciBarPrefetchable::Prefetchable => true,
|
||||
}
|
||||
|
||||
@@ -511,6 +511,16 @@ impl MsixCap {
|
||||
self.pba & 0xffff_fff8
|
||||
}
|
||||
|
||||
pub fn table_set_offset(&mut self, addr: u32) {
|
||||
self.table &= 0x7;
|
||||
self.table += addr;
|
||||
}
|
||||
|
||||
pub fn pba_set_offset(&mut self, addr: u32) {
|
||||
self.pba &= 0x7;
|
||||
self.pba += addr;
|
||||
}
|
||||
|
||||
pub fn table_bir(&self) -> u32 {
|
||||
self.table & 0x7
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
use anyhow::anyhow;
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use hypervisor::HypervisorVmError;
|
||||
use libc::{sysconf, _SC_PAGESIZE};
|
||||
use std::any::Any;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io;
|
||||
@@ -27,6 +28,9 @@ use vfio_bindings::bindings::vfio::*;
|
||||
use vfio_ioctls::{
|
||||
VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap, VfioRegionSparseMmapArea,
|
||||
};
|
||||
use vm_allocator::page_size::{
|
||||
align_page_size_down, align_page_size_up, is_4k_aligned, is_4k_multiple, is_page_size_aligned,
|
||||
};
|
||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
|
||||
@@ -498,6 +502,29 @@ impl VfioCommon {
|
||||
Ok(vfio_common)
|
||||
}
|
||||
|
||||
/// In case msix table offset is not page size aligned, we need do some fixup to achive it.
|
||||
/// Becuse we don't want the MMIO RW region and trap region overlap each other.
|
||||
fn fixup_msix_region(&mut self, bar_id: u32, region_size: u64) -> u64 {
|
||||
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||
let msix_cap = &mut msix.cap;
|
||||
|
||||
// Suppose table_bir equals to pba_bir here. Am I right?
|
||||
let (table_offset, table_size) = msix_cap.table_range();
|
||||
if is_page_size_aligned(table_offset) || msix_cap.table_bir() != bar_id {
|
||||
return region_size;
|
||||
}
|
||||
|
||||
let (pba_offset, pba_size) = msix_cap.pba_range();
|
||||
let msix_sz = align_page_size_up(table_size + pba_size);
|
||||
// Expand region to hold RW and trap region which both page size aligned
|
||||
let size = std::cmp::max(region_size * 2, msix_sz * 2);
|
||||
// let table starts from the middle of the region
|
||||
msix_cap.table_set_offset((size / 2) as u32);
|
||||
msix_cap.pba_set_offset((size / 2 + pba_offset - table_offset) as u32);
|
||||
|
||||
size
|
||||
}
|
||||
|
||||
pub(crate) fn allocate_bars(
|
||||
&mut self,
|
||||
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||
@@ -661,9 +688,16 @@ impl VfioCommon {
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
PciBarRegionType::Memory64BitRegion => {
|
||||
// BAR allocation must be naturally aligned
|
||||
// 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
|
||||
.allocate(restored_bar_addr, region_size, Some(region_size))
|
||||
.allocate(
|
||||
restored_bar_addr,
|
||||
region_size,
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
Some(unsafe { sysconf(_SC_PAGESIZE) as GuestUsize }),
|
||||
)
|
||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?
|
||||
}
|
||||
};
|
||||
@@ -800,6 +834,23 @@ impl VfioCommon {
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn get_msix_cap_idx(&self) -> Option<usize> {
|
||||
let mut cap_next = self
|
||||
.vfio_wrapper
|
||||
.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
||||
|
||||
while cap_next != 0 {
|
||||
let cap_id = self.vfio_wrapper.read_config_byte(cap_next.into());
|
||||
if PciCapabilityId::from(cap_id) == PciCapabilityId::MsiX {
|
||||
return Some(cap_next as usize);
|
||||
} else {
|
||||
cap_next = self.vfio_wrapper.read_config_byte((cap_next + 1).into());
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn parse_capabilities(&mut self, bdf: PciBdf) {
|
||||
let mut cap_next = self
|
||||
.vfio_wrapper
|
||||
@@ -1154,6 +1205,15 @@ impl VfioCommon {
|
||||
return self.configuration.read_reg(reg_idx);
|
||||
}
|
||||
|
||||
if let Some(id) = self.get_msix_cap_idx() {
|
||||
let msix = self.interrupt.msix.as_mut().unwrap();
|
||||
if reg_idx * 4 == id + 4 {
|
||||
return msix.cap.table;
|
||||
} else if reg_idx * 4 == id + 8 {
|
||||
return msix.cap.pba;
|
||||
}
|
||||
}
|
||||
|
||||
// Since we don't support passing multi-functions devices, we should
|
||||
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
||||
// register 3.
|
||||
@@ -1316,18 +1376,6 @@ impl VfioPciDevice {
|
||||
self.iommu_attached
|
||||
}
|
||||
|
||||
fn align_4k(address: u64) -> u64 {
|
||||
(address + 0xfff) & 0xffff_ffff_ffff_f000
|
||||
}
|
||||
|
||||
fn is_4k_aligned(address: u64) -> bool {
|
||||
(address & 0xfff) == 0
|
||||
}
|
||||
|
||||
fn is_4k_multiple(size: u64) -> bool {
|
||||
(size & 0xfff) == 0
|
||||
}
|
||||
|
||||
fn generate_sparse_areas(
|
||||
caps: &[VfioRegionInfoCap],
|
||||
region_index: u32,
|
||||
@@ -1339,14 +1387,14 @@ impl VfioPciDevice {
|
||||
match cap {
|
||||
VfioRegionInfoCap::SparseMmap(sparse_mmap) => return Ok(sparse_mmap.areas.clone()),
|
||||
VfioRegionInfoCap::MsixMappable => {
|
||||
if !Self::is_4k_aligned(region_start) {
|
||||
if !is_4k_aligned(region_start) {
|
||||
error!(
|
||||
"Region start address 0x{:x} must be at least aligned on 4KiB",
|
||||
region_start
|
||||
);
|
||||
return Err(VfioPciError::RegionAlignment);
|
||||
}
|
||||
if !Self::is_4k_multiple(region_size) {
|
||||
if !is_4k_multiple(region_size) {
|
||||
error!(
|
||||
"Region size 0x{:x} must be at least a multiple of 4KiB",
|
||||
region_size
|
||||
@@ -1358,7 +1406,8 @@ impl VfioPciDevice {
|
||||
// the MSI-X PBA table, we must calculate the subregions
|
||||
// around them, leading to a list of sparse areas.
|
||||
// We want to make sure we will still trap MMIO accesses
|
||||
// to these MSI-X specific ranges.
|
||||
// to these MSI-X specific ranges. If these region don't align
|
||||
// with pagesize, we can achive it by enlarging its range.
|
||||
//
|
||||
// Using a BtreeMap as the list provided through the iterator is sorted
|
||||
// by key. This ensures proper split of the whole region.
|
||||
@@ -1366,10 +1415,14 @@ impl VfioPciDevice {
|
||||
if let Some(msix) = vfio_msix {
|
||||
if region_index == msix.cap.table_bir() {
|
||||
let (offset, size) = msix.cap.table_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
if region_index == msix.cap.pba_bir() {
|
||||
let (offset, size) = msix.cap.pba_range();
|
||||
let offset = align_page_size_down(offset);
|
||||
let size = align_page_size_up(size);
|
||||
inter_ranges.insert(offset, size);
|
||||
}
|
||||
}
|
||||
@@ -1383,8 +1436,7 @@ impl VfioPciDevice {
|
||||
size: range_offset - current_offset,
|
||||
});
|
||||
}
|
||||
|
||||
current_offset = Self::align_4k(range_offset + range_size);
|
||||
current_offset = align_page_size_down(range_offset + range_size);
|
||||
}
|
||||
|
||||
if region_size > current_offset {
|
||||
@@ -1482,6 +1534,15 @@ impl VfioPciDevice {
|
||||
return Err(VfioPciError::MmapArea);
|
||||
}
|
||||
|
||||
if !is_page_size_aligned(area.size) || !is_page_size_aligned(area.offset) {
|
||||
warn!(
|
||||
"Could not mmap sparse area that is not page size aligned (offset = 0x{:x}, size = 0x{:x})",
|
||||
area.offset,
|
||||
area.size,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let user_memory_region = UserMemoryRegion {
|
||||
slot: (self.memory_slot)(),
|
||||
start: region.start.0 + area.offset,
|
||||
|
||||
@@ -7,9 +7,9 @@ build = "../build.rs"
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.9"
|
||||
dirs = "4.0.0"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.93"
|
||||
dirs = "5.0.0"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
test_infra = { path = "../test_infra" }
|
||||
thiserror = "1.0.38"
|
||||
thiserror = "1.0.40"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -110,18 +110,23 @@ impl Default for MetricsReport {
|
||||
#[derive(Default)]
|
||||
pub struct PerformanceTestOverrides {
|
||||
test_iterations: Option<u32>,
|
||||
test_timeout: Option<u32>,
|
||||
}
|
||||
|
||||
impl fmt::Display for PerformanceTestOverrides {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if let Some(test_iterations) = self.test_iterations {
|
||||
write!(f, "test_iterations = {test_iterations}")?;
|
||||
write!(f, "test_iterations = {test_iterations}, ")?;
|
||||
}
|
||||
if let Some(test_timeout) = self.test_timeout {
|
||||
write!(f, "test_timeout = {test_timeout}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PerformanceTestControl {
|
||||
test_timeout: u32,
|
||||
test_iterations: u32,
|
||||
@@ -188,7 +193,14 @@ impl PerformanceTest {
|
||||
.test_iterations
|
||||
.unwrap_or(self.control.test_iterations)
|
||||
{
|
||||
metrics.push((self.func_ptr)(&self.control));
|
||||
// update the timeout in control if passed explicitly and run testcase with it
|
||||
if let Some(test_timeout) = overrides.test_timeout {
|
||||
let mut control: PerformanceTestControl = self.control.clone();
|
||||
control.test_timeout = test_timeout;
|
||||
metrics.push((self.func_ptr)(&control));
|
||||
} else {
|
||||
metrics.push((self.func_ptr)(&self.control));
|
||||
}
|
||||
}
|
||||
|
||||
let mean = (self.unit_adjuster)(mean(&metrics).unwrap());
|
||||
@@ -207,9 +219,9 @@ impl PerformanceTest {
|
||||
|
||||
// Calculate the timeout for each test
|
||||
// Note: To cover the setup/cleanup time, 20s is added for each iteration of the test
|
||||
pub fn calc_timeout(&self, test_iterations: &Option<u32>) -> u64 {
|
||||
((self.control.test_timeout + 20) * test_iterations.unwrap_or(self.control.test_iterations))
|
||||
as u64
|
||||
pub fn calc_timeout(&self, test_iterations: &Option<u32>, test_timeout: &Option<u32>) -> u64 {
|
||||
((test_timeout.unwrap_or(self.control.test_timeout) + 20)
|
||||
* test_iterations.unwrap_or(self.control.test_iterations)) as u64
|
||||
}
|
||||
}
|
||||
|
||||
@@ -587,6 +599,7 @@ fn run_test_with_timeout(
|
||||
) -> Result<PerformanceTestResult, Error> {
|
||||
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
|
||||
let test_iterations = overrides.test_iterations;
|
||||
let test_timeout = overrides.test_timeout;
|
||||
let overrides = overrides.clone();
|
||||
thread::spawn(move || {
|
||||
println!(
|
||||
@@ -609,7 +622,7 @@ fn run_test_with_timeout(
|
||||
});
|
||||
|
||||
// Todo: Need to cleanup/kill all hanging child processes
|
||||
let test_timeout = test.calc_timeout(&test_iterations);
|
||||
let test_timeout = test.calc_timeout(&test_iterations, &test_timeout);
|
||||
receiver
|
||||
.recv_timeout(Duration::from_secs(test_timeout))
|
||||
.map_err(|_| {
|
||||
@@ -645,6 +658,10 @@ struct Options {
|
||||
/// override number of test iterations
|
||||
iterations: Option<u32>,
|
||||
|
||||
#[argh(option, long = "timeout")]
|
||||
/// override test timeout, Ex. --timeout 5
|
||||
timeout: Option<u32>,
|
||||
|
||||
#[argh(switch, short = 'V', long = "version")]
|
||||
/// print version information
|
||||
version: bool,
|
||||
@@ -654,7 +671,7 @@ fn main() {
|
||||
let opts: Options = argh::from_env();
|
||||
|
||||
if opts.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -683,6 +700,7 @@ fn main() {
|
||||
|
||||
let overrides = Arc::new(PerformanceTestOverrides {
|
||||
test_iterations: opts.iterations,
|
||||
test_timeout: opts.timeout,
|
||||
});
|
||||
|
||||
for test in test_list.iter() {
|
||||
|
||||
@@ -66,7 +66,7 @@ impl QcowRawFile {
|
||||
non_zero_flags: u64,
|
||||
) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u64>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
for addr in table {
|
||||
let val = if *addr == 0 {
|
||||
0
|
||||
@@ -91,7 +91,8 @@ impl QcowRawFile {
|
||||
/// Writes a refcount block to the file.
|
||||
pub fn write_refcount_block(&mut self, offset: u64, table: &[u16]) -> io::Result<()> {
|
||||
self.file.seek(SeekFrom::Start(offset))?;
|
||||
let mut buffer = BufWriter::with_capacity(table.len() * size_of::<u16>(), &mut self.file);
|
||||
let mut buffer = BufWriter::with_capacity(std::mem::size_of_val(table), &mut self.file);
|
||||
|
||||
for count in table {
|
||||
buffer.write_u16::<BigEndian>(*count)?;
|
||||
}
|
||||
|
||||
279
release-notes.md
279
release-notes.md
@@ -1,11 +1,29 @@
|
||||
- [v30.1](#v301)
|
||||
- [v33.0](#v330)
|
||||
- [D-Bus based API](#d-bus-based-api)
|
||||
- [Passthrough CPU cache information for AArch64](#passthrough-cpu-cache-information-for-aarch64)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [v32.0](#v320)
|
||||
- [Increased PCI Segment Limit](#increased-pci-segment-limit)
|
||||
- [API Changes](#api-changes)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Contributors](#contributors-1)
|
||||
- [v31.1](#v311)
|
||||
- [v31.0](#v310)
|
||||
- [Update to Latest `acpi_tables`](#update-to-latest-acpi_tables)
|
||||
- [Update Reference Kernel to 6.2](#update-reference-kernel-to-62)
|
||||
- [Improvements on Console `SIGWINCH` Handler](#improvements-on-console-sigwinch-handler)
|
||||
- [Remove Directory Support from `MemoryZoneConfig::file`](#remove-directory-support-from-memoryzoneconfigfile)
|
||||
- [Documentation Improvements](#documentation-improvements)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Contributors](#contributors-2)
|
||||
- [v30.0](#v300)
|
||||
- [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)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||
- [Contributors](#contributors)
|
||||
- [Documentation Improvements](#documentation-improvements-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-3)
|
||||
- [Contributors](#contributors-3)
|
||||
- [v28.2](#v282)
|
||||
- [v29.0](#v290)
|
||||
- [Release Binary Supports Both MSHV and KVM](#release-binary-supports-both-mshv-and-kvm)
|
||||
@@ -15,10 +33,10 @@
|
||||
- [`AArch64` Documentation Integration](#aarch64-documentation-integration)
|
||||
- [`virtio-block` Counters Enhancement](#virtio-block-counters-enhancement)
|
||||
- [TCP Offload Control](#tcp-offload-control)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-1)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Removals](#removals)
|
||||
- [Deprecations](#deprecations)
|
||||
- [Contributors](#contributors-1)
|
||||
- [Contributors](#contributors-4)
|
||||
- [v28.1](#v281)
|
||||
- [v28.0](#v280)
|
||||
- [Community Engagement (Reminder)](#community-engagement-reminder)
|
||||
@@ -26,9 +44,9 @@
|
||||
- [Virtualised TPM Support](#virtualised-tpm-support)
|
||||
- [Transparent Huge Page Support](#transparent-huge-page-support)
|
||||
- [README Quick Start Improved](#readme-quick-start-improved)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-2)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Removals](#removals-1)
|
||||
- [Contributors](#contributors-2)
|
||||
- [Contributors](#contributors-5)
|
||||
- [v27.0](#v270)
|
||||
- [Community Engagement](#community-engagement)
|
||||
- [Prebuilt Packages](#prebuilt-packages)
|
||||
@@ -37,41 +55,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-3)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
||||
- [Deprecations](#deprecations-1)
|
||||
- [Contributors](#contributors-3)
|
||||
- [Contributors](#contributors-6)
|
||||
- [v26.0](#v260)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via-platform)
|
||||
- [SMBIOS Improvements via `--platform`](#smbios-improvements-via---platform)
|
||||
- [Unified Binary MSHV and KVM Support](#unified-binary-mshv-and-kvm-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-4)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||
- [Deprecations](#deprecations-2)
|
||||
- [Removals](#removals-2)
|
||||
- [Contributors](#contributors-4)
|
||||
- [Contributors](#contributors-7)
|
||||
- [v25.0](#v250)
|
||||
- [`ch-remote` Improvements](#ch-remote-improvements-1)
|
||||
- [VM "Coredump" Support](#vm-coredump-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||
- [Removals](#removals-3)
|
||||
- [Contributors](#contributors-5)
|
||||
- [Contributors](#contributors-8)
|
||||
- [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-6)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||
- [Notable Improvements](#notable-improvements)
|
||||
- [Deprecations](#deprecations-3)
|
||||
- [New on the Website](#new-on-the-website)
|
||||
- [Contributors](#contributors-6)
|
||||
- [Contributors](#contributors-9)
|
||||
- [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-7)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||
- [Deprecations](#deprecations-4)
|
||||
- [Contributors](#contributors-7)
|
||||
- [Contributors](#contributors-10)
|
||||
- [v22.1](#v221)
|
||||
- [v22.0](#v220)
|
||||
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||
@@ -82,13 +100,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-8)
|
||||
- [Contributors](#contributors-8)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [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-9)
|
||||
- [Contributors](#contributors-9)
|
||||
- [Notable Bug fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [v20.2](#v202)
|
||||
- [v20.1](#v201)
|
||||
- [v20.0](#v200)
|
||||
@@ -97,8 +115,8 @@
|
||||
- [Improved VFIO support](#improved-vfio-support)
|
||||
- [Safer code](#safer-code)
|
||||
- [Extended documentation](#extended-documentation)
|
||||
- [Notable bug fixes](#notable-bug-fixes-10)
|
||||
- [Contributors](#contributors-10)
|
||||
- [Notable bug fixes](#notable-bug-fixes-13)
|
||||
- [Contributors](#contributors-13)
|
||||
- [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)
|
||||
@@ -106,8 +124,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-11)
|
||||
- [Contributors](#contributors-11)
|
||||
- [Notable bug fixes](#notable-bug-fixes-14)
|
||||
- [Contributors](#contributors-14)
|
||||
- [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)
|
||||
@@ -117,31 +135,31 @@
|
||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||
- [Notable bug fixes](#notable-bug-fixes-12)
|
||||
- [Contributors](#contributors-12)
|
||||
- [Notable bug fixes](#notable-bug-fixes-15)
|
||||
- [Contributors](#contributors-15)
|
||||
- [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-13)
|
||||
- [Contributors](#contributors-13)
|
||||
- [Notable bug fixes](#notable-bug-fixes-16)
|
||||
- [Contributors](#contributors-16)
|
||||
- [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-14)
|
||||
- [Notable bug fixes](#notable-bug-fixes-17)
|
||||
- [Removed functionality](#removed-functionality)
|
||||
- [Contributors](#contributors-14)
|
||||
- [Contributors](#contributors-17)
|
||||
- [v15.0](#v150)
|
||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||
- [Network device rate limiting](#network-device-rate-limiting)
|
||||
- [Support for runtime control of `virtio-net` guest offload](#support-for-runtime-control-of-virtio-net-guest-offload)
|
||||
- [`--api-socket` supports file descriptor parameter](#-api-socket-supports-file-descriptor-parameter)
|
||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||
- [Bug fixes](#bug-fixes)
|
||||
- [Deprecations](#deprecations-5)
|
||||
- [Contributors](#contributors-15)
|
||||
- [Contributors](#contributors-18)
|
||||
- [v0.14.1](#v0141)
|
||||
- [v0.14.0](#v0140)
|
||||
- [Structured event monitoring](#structured-event-monitoring)
|
||||
@@ -151,7 +169,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-16)
|
||||
- [Contributors](#contributors-19)
|
||||
- [v0.13.0](#v0130)
|
||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||
- [Improved huge page support](#improved-huge-page-support)
|
||||
@@ -159,13 +177,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-17)
|
||||
- [Contributors](#contributors-20)
|
||||
- [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-18)
|
||||
- [Contributors](#contributors-21)
|
||||
- [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)
|
||||
@@ -175,17 +193,17 @@
|
||||
- [Improved Linux Boot Time](#improved-linux-boot-time)
|
||||
- [`SIGTERM/SIGINT` Interrupt Signal Handling](#sigtermsigint-interrupt-signal-handling)
|
||||
- [Default Log Level Changed](#default-log-level-changed)
|
||||
- [New `--balloon` Parameter Added](#new-balloon-parameter-added)
|
||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-15)
|
||||
- [Contributors](#contributors-19)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-18)
|
||||
- [Contributors](#contributors-22)
|
||||
- [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-16)
|
||||
- [Contributors](#contributors-20)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-19)
|
||||
- [Contributors](#contributors-23)
|
||||
- [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)
|
||||
@@ -198,17 +216,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-17)
|
||||
- [Contributors](#contributors-21)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-20)
|
||||
- [Contributors](#contributors-24)
|
||||
- [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-18)
|
||||
- [Notable Bug Fixes](#notable-bug-fixes-21)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||
- [Contributors](#contributors-22)
|
||||
- [Contributors](#contributors-25)
|
||||
- [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)
|
||||
@@ -218,14 +236,14 @@
|
||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||
- [Updated Distribution Support](#updated-distribution-support)
|
||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||
- [Contributors](#contributors-23)
|
||||
- [Contributors](#contributors-26)
|
||||
- [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-24)
|
||||
- [Contributors](#contributors-27)
|
||||
- [v0.5.1](#v051)
|
||||
- [v0.5.0](#v050)
|
||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||
@@ -233,7 +251,7 @@
|
||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||
- [Development Tools](#development-tools)
|
||||
- [Kata Containers Integration](#kata-containers-integration)
|
||||
- [Contributors](#contributors-25)
|
||||
- [Contributors](#contributors-28)
|
||||
- [v0.4.0](#v040)
|
||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||
@@ -242,7 +260,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-26)
|
||||
- [Contributors](#contributors-29)
|
||||
- [v0.3.0](#v030)
|
||||
- [Block device offloading](#block-device-offloading)
|
||||
- [Network device backend](#network-device-backend)
|
||||
@@ -269,7 +287,94 @@
|
||||
- [Unit testing](#unit-testing)
|
||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||
|
||||
# v30.1
|
||||
# v33.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v33.0. The following user visible changes have been made:
|
||||
|
||||
### D-Bus based API
|
||||
|
||||
A D-Bus based API has been added as an alternative to the existing REST
|
||||
API. This feature is gated by the `dbus_api` feature. Details can be
|
||||
found in the [API documentation](docs/api.md).
|
||||
|
||||
### Expose Host CPU Cache Details for AArch64
|
||||
|
||||
Now the CPU cache information on the host is properly exposed to the
|
||||
guest on AArch64.
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Report errors explicitly to users when VM failed to boot (#5453)
|
||||
* Fix VFIO on platforms with non-4k page size (#5450, #5469)
|
||||
* Fix TDX initialization (#5454)
|
||||
* Ensure all guest memory regions are page-size aligned (#5496)
|
||||
* Fix seccomp filter lists related to virtio-console, serial and pty
|
||||
(#5506, #5524)
|
||||
* Populate APIC ID properly (#5512)
|
||||
* Ignore and warn TAP FDs in more situations (#5522)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Jianyong Wu <jianyong.wu@arm.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Yu Li <liyu.yukiteru@bytedance.com>
|
||||
* zhongbingnan <zhongbingnan@bytedance.com>
|
||||
|
||||
# v32.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v32.0. The following user visible changes have been made:
|
||||
|
||||
### Increased PCI Segment Limit
|
||||
|
||||
The maximum number of PCI segments that can be used is now 96 (up from 16).
|
||||
|
||||
### API Changes
|
||||
|
||||
* The VmmPingResponse now includes the PID as well as the build details.
|
||||
(#5348)
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Ignore and warn TAP FDs sent via the HTTP request body (#5350)
|
||||
* Properly preserve and close valid FDs for TAP devices (#5373)
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
* The number of vCPUs is capped at the hypervisor maximum (#5357)
|
||||
* Fixes for TTY reset (#5414)
|
||||
* CPU topology fixes on MSHV (#5325)
|
||||
* Seccomp fixes for older distributions (#5397)
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Hao Xu <howeyxu@tencent.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Rafael Mendonca <rafaelmendsr@gmail.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Smit Gardhariya <gardhariya.smit@gmail.com>
|
||||
* Wei Liu <liuwe@microsoft.com>
|
||||
|
||||
# v31.1
|
||||
|
||||
This is a bug fix release. The following issues have been addressed:
|
||||
|
||||
@@ -278,10 +383,72 @@ This is a bug fix release. The following issues have been addressed:
|
||||
* Only use `KVM_ARM_VCPU_PMU_V3` if available (#5360)
|
||||
* Only touch the tty flags if it's being used (#5343)
|
||||
* Fix seccomp filter lists for vhost-user devices (#5361)
|
||||
* Fix the offset setting while removing the entire mapping of
|
||||
`vhost-user` FS client (#5235)
|
||||
* Fix the `ShutdownVmm` and `Shutdown` commands to call the correct API
|
||||
endpoint (#5322)
|
||||
|
||||
# v31.0
|
||||
|
||||
This release has been tracked in our [roadmap
|
||||
project](https://github.com/orgs/cloud-hypervisor/projects/6) as iteration
|
||||
v31.0. The following user visible changes have been made:
|
||||
|
||||
### Update to Latest `acpi_tables`
|
||||
|
||||
Adapted to the latest [acpi_tables](https://github.com/rust-vmm/acpi_tables).
|
||||
There has been significant API changes in the crate.
|
||||
|
||||
### Update Reference Kernel to 6.2
|
||||
|
||||
Updated the recommended guest kernel version from 6.1.6 to 6.2.
|
||||
|
||||
### Improvements on Console `SIGWINCH` Handler
|
||||
|
||||
A separate thread had been created to capture the `SIGWINCH` signal and resize
|
||||
the guest console. Now the thread is skipped if the console is not resizable.
|
||||
|
||||
Two completely different code paths existed for handling console resizing, one
|
||||
for `tty` and the other for `pty`. That makes the understanding of the console
|
||||
handling code unnecessarily complicated. Now the code paths are unified. Both
|
||||
`tty` and `pty` are supported in single `SIGWINCH` handler. And the new handler
|
||||
can works with kernel versions earlier than v5.5.
|
||||
|
||||
### Remove Directory Support from `MemoryZoneConfig::file`
|
||||
|
||||
Setting a directory to `MemoryZoneConfig::file` is no longer supported.
|
||||
|
||||
Before this change, user can set a directory to `file` of the `--memory-zone`
|
||||
option. In that case, a temporary file will be created as the backing file for
|
||||
the `mmap(2)` operation. This functionality has been unnecessary since we had
|
||||
the native support for hugepages and allocating anonymous shared memory.
|
||||
|
||||
### Documentation Improvements
|
||||
|
||||
* Various improvements in API document
|
||||
* Improvements in Doc comments
|
||||
* Updated Slack channel information in README
|
||||
|
||||
### Notable Bug Fixes
|
||||
|
||||
* Fixed the offset setting while removing the entire mapping of `vhost-user` FS
|
||||
client.
|
||||
* Fixed the `ShutdownVmm` and `Shutdown` commands to call the correct API
|
||||
endpoint.
|
||||
|
||||
### Contributors
|
||||
|
||||
Many thanks to everyone who has contributed to our release:
|
||||
|
||||
* Alyssa Ross <hi@alyssa.is>
|
||||
* Bo Chen <chen.bo@intel.com>
|
||||
* Daniel Farina <daniel@fdr.io>
|
||||
* Dom <peng6662001@163.com>
|
||||
* Hao Xu <howeyxu@tencent.com>
|
||||
* Muminul Islam <muislam@microsoft.com>
|
||||
* Omer Faruk Bayram <omer.faruk@sartura.hr>
|
||||
* Ravi kumar Veeramally <ravikumar.veeramally@intel.com>
|
||||
* Rob Bradford <rbradford@rivosinc.com>
|
||||
* Ruslan Mstoi <ruslan.mstoi@intel.com>
|
||||
* Smit Gardhariya <gardhariya.smit@gmail.com>
|
||||
* Yang <ailin.yang@intel.com>
|
||||
* Yong He <alexyonghe@tencent.com>
|
||||
|
||||
# v30.0
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# 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
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG RUST_TOOLCHAIN="1.66.1"
|
||||
ARG RUST_TOOLCHAIN="1.67.1"
|
||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||
@@ -13,58 +15,67 @@ ARG CARGO_GIT_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_git_registry"
|
||||
ENV CARGO_HOME=/usr/local/rust
|
||||
ENV RUSTUP_HOME=$CARGO_HOME
|
||||
ENV PATH="$PATH:$CARGO_HOME/bin"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install all CI dependencies
|
||||
# DL3015 ignored cause not installing openvswitch-switch-dpdk recommended packages breaks ovs_dpdk test
|
||||
# hadolint ignore=DL3008,DL3015
|
||||
RUN apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
openvswitch-switch-dpdk \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
build-essential \
|
||||
bc \
|
||||
curl \
|
||||
wget \
|
||||
sudo \
|
||||
mtools \
|
||||
musl-tools \
|
||||
libssl-dev \
|
||||
pkg-config \
|
||||
flex \
|
||||
bison \
|
||||
libelf-dev \
|
||||
qemu-utils \
|
||||
libglib2.0-dev \
|
||||
libpixman-1-dev \
|
||||
libseccomp-dev \
|
||||
libcap-ng-dev \
|
||||
socat \
|
||||
dosfstools \
|
||||
cpio \
|
||||
python \
|
||||
python3 \
|
||||
python3-setuptools \
|
||||
ntfs-3g \
|
||||
python3-distutils \
|
||||
uuid-dev \
|
||||
iperf3 \
|
||||
zip \
|
||||
git-core \
|
||||
dnsmasq \
|
||||
dmsetup \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
iproute2 \
|
||||
dbus \
|
||||
&& apt-get install openvswitch-switch-dpdk -yq \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old
|
||||
|
||||
RUN update-alternatives --set ovs-vswitchd /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq gcc-multilib gawk \
|
||||
libtool expect gnutls-dev gnutls-bin libfuse-dev \
|
||||
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
|
||||
net-tools softhsm2 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& apt-get install --no-install-recommends -yq gcc-multilib gawk \
|
||||
libtool expect gnutls-dev gnutls-bin libfuse-dev \
|
||||
libjson-glib-dev libgmp-dev libtasn1-dev python3-twisted \
|
||||
net-tools softhsm2 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# On AArch64, `setcap` binary should be installed via `libcap2-bin`.
|
||||
# The `setcap` binary is used in integration tests.
|
||||
@@ -72,7 +83,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
# kernel (any version) image in `/boot` and modules in `/lib/modules`.
|
||||
apt-get update \
|
||||
&& apt-get -yq upgrade \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||
&& apt-get install --no-install-recommends -yq \
|
||||
libcap2-bin \
|
||||
libguestfs-tools \
|
||||
linux-image-generic \
|
||||
@@ -82,11 +93,12 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
perl \
|
||||
texinfo \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*; fi
|
||||
&& rm -rf /var/lib/apt/lists/* /var/log/*log /var/log/apt/* /var/lib/dpkg/*-old /var/cache/debconf/*-old; fi
|
||||
|
||||
# Fix the libssl-dev install
|
||||
# hadolint ignore=SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& cp /usr/include/$ARCH-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
&& cp /usr/include/"$ARCH"-linux-gnu/openssl/opensslconf.h /usr/include/openssl/
|
||||
ENV X86_64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV X86_64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/x86_64-linux-gnu/
|
||||
ENV AARCH64_UNKNOWN_LINUX_GNU_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
@@ -94,9 +106,10 @@ ENV AARCH64_UNKNOWN_LINUX_MUSL_OPENSSL_LIB_DIR=/usr/lib/aarch64-linux-gnu/
|
||||
ENV OPENSSL_INCLUDE_DIR=/usr/include/
|
||||
|
||||
# Install the rust toolchain
|
||||
# hadolint ignore=DL4006,SC2155
|
||||
RUN export ARCH="$(uname -m)" \
|
||||
&& nohup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add $ARCH-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& rustup target add "$ARCH"-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup toolchain add --profile minimal $RUST_TOOLCHAIN-x86_64-unknown-linux-musl; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add rustfmt; fi \
|
||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
|
||||
@@ -106,12 +119,14 @@ RUN export ARCH="$(uname -m)" \
|
||||
&& ln -s "$CARGO_GIT_REGISTRY_DIR" "$CARGO_HOME/git"
|
||||
|
||||
# Set the rust environment
|
||||
RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
||||
&& mkdir $HOME/.cargo \
|
||||
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
||||
# hadolint ignore=SC2016
|
||||
RUN echo 'source $CARGO_HOME/env' >> "$HOME"/.bashrc \
|
||||
&& mkdir "$HOME"/.cargo \
|
||||
&& ln -s $CARGO_HOME/env "$HOME"/.cargo/env
|
||||
|
||||
# install SPDK NVMe
|
||||
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
|
||||
# hadolint ignore=DL3003,SC2046
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/spdk/spdk \
|
||||
&& cd spdk \
|
||||
@@ -121,7 +136,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
&& ./scripts/pkgdep.sh \
|
||||
&& apt-get clean \
|
||||
&& ./configure --with-vfio-user \
|
||||
&& make -j `nproc` \
|
||||
&& make -j $(nproc) \
|
||||
&& mkdir /usr/local/bin/spdk-nvme \
|
||||
&& cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme \
|
||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||
@@ -129,6 +144,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
&& cd .. && rm -rf spdk; fi
|
||||
|
||||
# install swtpm only for x86_64 arch
|
||||
# hadolint ignore=DL3003
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
git clone https://github.com/stefanberger/libtpms libtpms_build \
|
||||
&& cd libtpms_build \
|
||||
@@ -149,7 +165,7 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
|
||||
# install ethr tool for performance tests
|
||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||
wget https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
wget -nv https://github.com/microsoft/ethr/releases/latest/download/ethr_linux.zip \
|
||||
&& unzip ethr_linux.zip \
|
||||
&& cp ethr /usr/local/bin \
|
||||
&& rm ethr_linux.zip; fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/arm64 6.1.6 Kernel Configuration
|
||||
# Linux/arm64 6.2.0 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
@@ -55,7 +55,6 @@ CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_GENERIC_IRQ_IPI=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_MSI_IOMMU=y
|
||||
CONFIG_IRQ_FORCED_THREADING=y
|
||||
CONFIG_SPARSE_IRQ=y
|
||||
@@ -203,6 +202,7 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
CONFIG_LD_ORPHAN_WARN=y
|
||||
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_EXPERT=y
|
||||
@@ -227,6 +227,7 @@ CONFIG_IO_URING=y
|
||||
CONFIG_ADVISE_SYSCALLS=y
|
||||
CONFIG_MEMBARRIER=y
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_SELFTEST is not set
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
CONFIG_KALLSYMS_BASE_RELATIVE=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
@@ -249,7 +250,7 @@ CONFIG_PERF_EVENTS=y
|
||||
# end of General setup
|
||||
|
||||
CONFIG_ARM64=y
|
||||
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_GCC_SUPPORTS_DYNAMIC_FTRACE_WITH_ARGS=y
|
||||
CONFIG_64BIT=y
|
||||
CONFIG_MMU=y
|
||||
CONFIG_ARM64_PAGE_SHIFT=12
|
||||
@@ -349,6 +350,7 @@ CONFIG_ARM64_ERRATUM_2054223=y
|
||||
CONFIG_ARM64_ERRATUM_2067961=y
|
||||
CONFIG_ARM64_ERRATUM_2441009=y
|
||||
CONFIG_ARM64_ERRATUM_2457168=y
|
||||
CONFIG_ARM64_ERRATUM_2645198=y
|
||||
CONFIG_CAVIUM_ERRATUM_22375=y
|
||||
CONFIG_CAVIUM_ERRATUM_23144=y
|
||||
CONFIG_CAVIUM_ERRATUM_23154=y
|
||||
@@ -376,7 +378,7 @@ CONFIG_ARM64_PA_BITS=48
|
||||
# CONFIG_CPU_BIG_ENDIAN is not set
|
||||
CONFIG_CPU_LITTLE_ENDIAN=y
|
||||
CONFIG_SCHED_MC=y
|
||||
CONFIG_SCHED_CLUSTER is not set
|
||||
# CONFIG_SCHED_CLUSTER is not set
|
||||
CONFIG_SCHED_SMT=y
|
||||
CONFIG_NR_CPUS=128
|
||||
CONFIG_HOTPLUG_CPU=y
|
||||
@@ -471,7 +473,6 @@ CONFIG_RANDOMIZE_BASE=y
|
||||
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
|
||||
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
|
||||
CONFIG_STACKPROTECTOR_PER_TASK=y
|
||||
CONFIG_ARCH_NR_GPIO=0
|
||||
# end of Kernel Features
|
||||
|
||||
#
|
||||
@@ -559,6 +560,7 @@ CONFIG_ACPI_GENERIC_GSI=y
|
||||
CONFIG_ACPI_CCA_REQUIRED=y
|
||||
# CONFIG_ACPI_DEBUGGER is not set
|
||||
CONFIG_ACPI_SPCR_TABLE=y
|
||||
# CONFIG_ACPI_FPDT is not set
|
||||
# CONFIG_ACPI_EC_DEBUGFS is not set
|
||||
# CONFIG_ACPI_AC is not set
|
||||
# CONFIG_ACPI_BATTERY is not set
|
||||
@@ -591,8 +593,10 @@ CONFIG_HAVE_ACPI_APEI=y
|
||||
# CONFIG_ACPI_PFRUT is not set
|
||||
CONFIG_ACPI_IORT=y
|
||||
CONFIG_ACPI_GTDT=y
|
||||
CONFIG_ACPI_APMT=y
|
||||
CONFIG_ACPI_PPTT=y
|
||||
# CONFIG_ACPI_PCC is not set
|
||||
# CONFIG_ACPI_FFH is not set
|
||||
# CONFIG_PMIC_OPREGION is not set
|
||||
CONFIG_ACPI_VIOT=y
|
||||
# CONFIG_ACPI_PRMT is not set
|
||||
@@ -601,6 +605,9 @@ CONFIG_HAVE_KVM=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_HAVE_KVM_IRQFD=y
|
||||
CONFIG_HAVE_KVM_IRQ_ROUTING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
|
||||
CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP=y
|
||||
CONFIG_HAVE_KVM_EVENTFD=y
|
||||
CONFIG_KVM_MMIO=y
|
||||
CONFIG_HAVE_KVM_MSI=y
|
||||
@@ -654,6 +661,7 @@ CONFIG_HAVE_ARCH_JUMP_LABEL_RELATIVE=y
|
||||
CONFIG_MMU_GATHER_TABLE_FREE=y
|
||||
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
|
||||
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
@@ -718,6 +726,7 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
# end of GCOV-based kernel profiling
|
||||
|
||||
CONFIG_HAVE_GCC_PLUGINS=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=0
|
||||
# end of General architecture-dependent options
|
||||
|
||||
CONFIG_RT_MUTEXES=y
|
||||
@@ -884,7 +893,8 @@ CONFIG_ZSMALLOC_STAT=y
|
||||
#
|
||||
# CONFIG_SLAB is not set
|
||||
CONFIG_SLUB=y
|
||||
# CONFIG_SLOB is not set
|
||||
# CONFIG_SLOB_DEPRECATED is not set
|
||||
# CONFIG_SLUB_TINY is not set
|
||||
CONFIG_SLAB_MERGE_DEFAULT=y
|
||||
# CONFIG_SLAB_FREELIST_RANDOM is not set
|
||||
CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
@@ -951,6 +961,7 @@ CONFIG_ZONE_DMA32=y
|
||||
CONFIG_ZONE_DEVICE=y
|
||||
# CONFIG_DEVICE_PRIVATE is not set
|
||||
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
|
||||
CONFIG_ARCH_USES_PG_ARCH_X=y
|
||||
CONFIG_VM_EVENT_COUNTERS=y
|
||||
CONFIG_PERCPU_STATS=y
|
||||
# CONFIG_GUP_TEST is not set
|
||||
@@ -1122,7 +1133,6 @@ CONFIG_PCIE_PME=y
|
||||
# CONFIG_PCIE_DPC is not set
|
||||
# CONFIG_PCIE_PTM is not set
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PCI_QUIRKS=y
|
||||
CONFIG_PCI_DEBUG=y
|
||||
CONFIG_PCI_STUB=y
|
||||
@@ -1272,7 +1282,6 @@ CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB=y
|
||||
# CONFIG_EFI_ZBOOT is not set
|
||||
CONFIG_EFI_ARMSTUB_DTB_LOADER=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
@@ -1326,6 +1335,7 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
|
||||
CONFIG_ZRAM_DEF_COMP="lzo-rle"
|
||||
# CONFIG_ZRAM_WRITEBACK is not set
|
||||
# CONFIG_ZRAM_MEMORY_TRACKING is not set
|
||||
# CONFIG_ZRAM_MULTI_COMP is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
|
||||
# CONFIG_BLK_DEV_DRBD is not set
|
||||
@@ -1576,6 +1586,7 @@ CONFIG_HW_CONSOLE=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_UNIX98_PTYS=y
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_LEGACY_TIOCSTI is not set
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
|
||||
#
|
||||
@@ -1651,8 +1662,6 @@ CONFIG_DEVMEM=y
|
||||
CONFIG_DEVPORT=y
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||
# end of Character devices
|
||||
|
||||
#
|
||||
@@ -1741,6 +1750,7 @@ CONFIG_GPIO_PL061=y
|
||||
# Virtual GPIO drivers
|
||||
#
|
||||
# CONFIG_GPIO_AGGREGATOR is not set
|
||||
# CONFIG_GPIO_LATCH is not set
|
||||
# CONFIG_GPIO_MOCKUP is not set
|
||||
# CONFIG_GPIO_VIRTIO is not set
|
||||
# CONFIG_GPIO_SIM is not set
|
||||
@@ -2158,9 +2168,10 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
||||
# CONFIG_UIO_PRUSS is not set
|
||||
# CONFIG_UIO_MF624 is not set
|
||||
CONFIG_VFIO=y
|
||||
CONFIG_VFIO_CONTAINER=y
|
||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
# CONFIG_VFIO_NOIOMMU is not set
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
CONFIG_VFIO_PCI_CORE=y
|
||||
CONFIG_VFIO_PCI_MMAP=y
|
||||
CONFIG_VFIO_PCI_INTX=y
|
||||
@@ -2259,6 +2270,7 @@ CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
|
||||
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
||||
CONFIG_OF_IOMMU=y
|
||||
CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_IOMMUFD is not set
|
||||
# CONFIG_ARM_SMMU is not set
|
||||
# CONFIG_ARM_SMMU_V3 is not set
|
||||
CONFIG_VIRTIO_IOMMU=y
|
||||
@@ -2395,6 +2407,7 @@ CONFIG_ARM_PMU_ACPI=y
|
||||
# CONFIG_HISI_PMU is not set
|
||||
# CONFIG_HISI_PCIE_PMU is not set
|
||||
# CONFIG_HNS3_PMU is not set
|
||||
# CONFIG_ARM_CORESIGHT_PMU_ARCH_SYSTEM_PMU is not set
|
||||
# end of Performance monitor support
|
||||
|
||||
CONFIG_RAS=y
|
||||
@@ -2570,8 +2583,10 @@ CONFIG_SQUASHFS=y
|
||||
CONFIG_SQUASHFS_FILE_CACHE=y
|
||||
# CONFIG_SQUASHFS_FILE_DIRECT is not set
|
||||
CONFIG_SQUASHFS_DECOMP_SINGLE=y
|
||||
# CONFIG_SQUASHFS_DECOMP_MULTI is not set
|
||||
# CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU is not set
|
||||
# CONFIG_SQUASHFS_CHOICE_DECOMP_BY_MOUNT is not set
|
||||
CONFIG_SQUASHFS_COMPILE_DECOMP_SINGLE=y
|
||||
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI is not set
|
||||
# CONFIG_SQUASHFS_COMPILE_DECOMP_MULTI_PERCPU is not set
|
||||
# CONFIG_SQUASHFS_XATTR is not set
|
||||
CONFIG_SQUASHFS_ZLIB=y
|
||||
# CONFIG_SQUASHFS_LZ4 is not set
|
||||
@@ -2710,7 +2725,6 @@ CONFIG_CRYPTO_MANAGER2=y
|
||||
# CONFIG_CRYPTO_USER is not set
|
||||
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
|
||||
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
# CONFIG_CRYPTO_PCRYPT is not set
|
||||
@@ -2872,6 +2886,8 @@ CONFIG_CRYPTO_USER_API_RNG=y
|
||||
# CONFIG_CRYPTO_SM4_ARM64_CE_BLK is not set
|
||||
# CONFIG_CRYPTO_SM4_ARM64_NEON_BLK is not set
|
||||
# CONFIG_CRYPTO_AES_ARM64_CE_CCM is not set
|
||||
# CONFIG_CRYPTO_SM4_ARM64_CE_CCM is not set
|
||||
# CONFIG_CRYPTO_SM4_ARM64_CE_GCM is not set
|
||||
# CONFIG_CRYPTO_CRCT10DIF_ARM64_CE is not set
|
||||
# end of Accelerated Cryptographic Algorithms for CPU (arm64)
|
||||
|
||||
@@ -2910,6 +2926,7 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
|
||||
#
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_CRYPTO_LIB_AES=y
|
||||
CONFIG_CRYPTO_LIB_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
# CONFIG_CRYPTO_LIB_CHACHA is not set
|
||||
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
|
||||
@@ -3045,7 +3062,8 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
# CONFIG_DEBUG_INFO_DWARF4 is not set
|
||||
# CONFIG_DEBUG_INFO_DWARF5 is not set
|
||||
# CONFIG_DEBUG_INFO_REDUCED is not set
|
||||
# CONFIG_DEBUG_INFO_COMPRESSED is not set
|
||||
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
|
||||
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
|
||||
# CONFIG_DEBUG_INFO_SPLIT is not set
|
||||
# CONFIG_DEBUG_INFO_BTF is not set
|
||||
# CONFIG_GDB_SCRIPTS is not set
|
||||
@@ -3206,7 +3224,7 @@ CONFIG_RCU_EXP_CPU_STALL_TIMEOUT=0
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
@@ -3245,7 +3263,6 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_HEXDUMP is not set
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# CONFIG_TEST_STRING_HELPERS is not set
|
||||
# CONFIG_TEST_STRSCPY is not set
|
||||
# CONFIG_TEST_KSTRTOX is not set
|
||||
# CONFIG_TEST_PRINTF is not set
|
||||
# CONFIG_TEST_SCANF is not set
|
||||
@@ -3254,7 +3271,6 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_XARRAY is not set
|
||||
# CONFIG_TEST_MAPLE_TREE is not set
|
||||
# CONFIG_TEST_RHASHTABLE is not set
|
||||
# CONFIG_TEST_SIPHASH is not set
|
||||
# CONFIG_TEST_IDA is not set
|
||||
# CONFIG_FIND_BIT_BENCHMARK is not set
|
||||
# CONFIG_TEST_FIRMWARE is not set
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86 6.1.6 Kernel Configuration
|
||||
# Linux/x86 6.2.0 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4)"
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_GCC_VERSION=120201
|
||||
CONFIG_GCC_VERSION=110300
|
||||
CONFIG_CLANG_VERSION=0
|
||||
CONFIG_AS_IS_GNU=y
|
||||
CONFIG_AS_VERSION=23700
|
||||
CONFIG_AS_VERSION=23800
|
||||
CONFIG_LD_IS_BFD=y
|
||||
CONFIG_LD_VERSION=23700
|
||||
CONFIG_LD_VERSION=23800
|
||||
CONFIG_LLD_VERSION=0
|
||||
CONFIG_RUST_IS_AVAILABLE=y
|
||||
CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
@@ -70,7 +70,6 @@ CONFIG_HARDIRQS_SW_RESEND=y
|
||||
CONFIG_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_DOMAIN_HIERARCHY=y
|
||||
CONFIG_GENERIC_MSI_IRQ=y
|
||||
CONFIG_GENERIC_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_IRQ_MSI_IOMMU=y
|
||||
CONFIG_GENERIC_IRQ_MATRIX_ALLOCATOR=y
|
||||
CONFIG_GENERIC_IRQ_RESERVATION_MODE=y
|
||||
@@ -228,6 +227,7 @@ CONFIG_INITRAMFS_PRESERVE_MTIME=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
CONFIG_LD_ORPHAN_WARN=y
|
||||
CONFIG_LD_ORPHAN_WARN_LEVEL="warn"
|
||||
CONFIG_SYSCTL=y
|
||||
CONFIG_SYSCTL_EXCEPTION_TRACE=y
|
||||
CONFIG_HAVE_PCSPKR_PLATFORM=y
|
||||
@@ -254,6 +254,7 @@ CONFIG_IO_URING=y
|
||||
CONFIG_ADVISE_SYSCALLS=y
|
||||
CONFIG_MEMBARRIER=y
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_SELFTEST is not set
|
||||
# CONFIG_KALLSYMS_ALL is not set
|
||||
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
|
||||
CONFIG_KALLSYMS_BASE_RELATIVE=y
|
||||
@@ -274,7 +275,6 @@ CONFIG_PERF_EVENTS=y
|
||||
# end of Kernel Performance Events And Counters
|
||||
|
||||
# CONFIG_PROFILING is not set
|
||||
# CONFIG_RUST is not set
|
||||
# end of General setup
|
||||
|
||||
CONFIG_64BIT=y
|
||||
@@ -294,7 +294,6 @@ CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||
CONFIG_GENERIC_CALIBRATE_DELAY=y
|
||||
CONFIG_ARCH_HAS_CPU_RELAX=y
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
CONFIG_ARCH_NR_GPIO=1024
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
CONFIG_AUDIT_ARCH=y
|
||||
CONFIG_X86_64_SMP=y
|
||||
@@ -422,7 +421,10 @@ CONFIG_X86_INTEL_TSX_MODE_OFF=y
|
||||
# CONFIG_X86_SGX is not set
|
||||
CONFIG_EFI=y
|
||||
CONFIG_EFI_STUB=y
|
||||
# CONFIG_EFI_HANDOVER_PROTOCOL is not set
|
||||
# CONFIG_EFI_MIXED is not set
|
||||
# CONFIG_EFI_FAKE_MEMMAP is not set
|
||||
CONFIG_EFI_RUNTIME_MAP=y
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_250=y
|
||||
# CONFIG_HZ_300 is not set
|
||||
@@ -455,11 +457,20 @@ CONFIG_HAVE_LIVEPATCH=y
|
||||
|
||||
CONFIG_CC_HAS_SLS=y
|
||||
CONFIG_CC_HAS_RETURN_THUNK=y
|
||||
CONFIG_CC_HAS_ENTRY_PADDING=y
|
||||
CONFIG_FUNCTION_PADDING_CFI=11
|
||||
CONFIG_FUNCTION_PADDING_BYTES=16
|
||||
CONFIG_CALL_PADDING=y
|
||||
CONFIG_HAVE_CALL_THUNKS=y
|
||||
CONFIG_CALL_THUNKS=y
|
||||
CONFIG_PREFIX_SYMBOLS=y
|
||||
CONFIG_SPECULATION_MITIGATIONS=y
|
||||
CONFIG_PAGE_TABLE_ISOLATION=y
|
||||
CONFIG_RETPOLINE=y
|
||||
CONFIG_RETHUNK=y
|
||||
CONFIG_CPU_UNRET_ENTRY=y
|
||||
CONFIG_CALL_DEPTH_TRACKING=y
|
||||
# CONFIG_CALL_THUNKS_DEBUG is not set
|
||||
CONFIG_CPU_IBPB_ENTRY=y
|
||||
CONFIG_CPU_IBRS_ENTRY=y
|
||||
# CONFIG_SLS is not set
|
||||
@@ -533,6 +544,7 @@ CONFIG_HAVE_ACPI_APEI_NMI=y
|
||||
# CONFIG_ACPI_CONFIGFS is not set
|
||||
# CONFIG_ACPI_PFRUT is not set
|
||||
# CONFIG_ACPI_PCC is not set
|
||||
# CONFIG_ACPI_FFH is not set
|
||||
# CONFIG_PMIC_OPREGION is not set
|
||||
CONFIG_ACPI_VIOT=y
|
||||
# CONFIG_ACPI_PRMT is not set
|
||||
@@ -628,6 +640,7 @@ CONFIG_KVM=y
|
||||
# CONFIG_KVM_WERROR is not set
|
||||
CONFIG_KVM_INTEL=y
|
||||
# CONFIG_KVM_AMD is not set
|
||||
CONFIG_KVM_SMM=y
|
||||
# CONFIG_KVM_XEN is not set
|
||||
CONFIG_AS_AVX512=y
|
||||
CONFIG_AS_SHA1_NI=y
|
||||
@@ -684,6 +697,7 @@ CONFIG_MMU_GATHER_TABLE_FREE=y
|
||||
CONFIG_MMU_GATHER_RCU_TABLE_FREE=y
|
||||
CONFIG_MMU_GATHER_MERGE_VMAS=y
|
||||
CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
|
||||
CONFIG_ARCH_HAS_NMI_SAFE_THIS_CPU_OPS=y
|
||||
CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
|
||||
CONFIG_HAVE_CMPXCHG_LOCAL=y
|
||||
CONFIG_HAVE_CMPXCHG_DOUBLE=y
|
||||
@@ -765,6 +779,9 @@ CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
|
||||
# end of GCOV-based kernel profiling
|
||||
|
||||
CONFIG_HAVE_GCC_PLUGINS=y
|
||||
CONFIG_FUNCTION_ALIGNMENT_4B=y
|
||||
CONFIG_FUNCTION_ALIGNMENT_16B=y
|
||||
CONFIG_FUNCTION_ALIGNMENT=16
|
||||
# end of General architecture-dependent options
|
||||
|
||||
CONFIG_RT_MUTEXES=y
|
||||
@@ -882,7 +899,8 @@ CONFIG_ZSMALLOC_STAT=y
|
||||
#
|
||||
# CONFIG_SLAB is not set
|
||||
CONFIG_SLUB=y
|
||||
# CONFIG_SLOB is not set
|
||||
# CONFIG_SLOB_DEPRECATED is not set
|
||||
# CONFIG_SLUB_TINY is not set
|
||||
CONFIG_SLAB_MERGE_DEFAULT=y
|
||||
# CONFIG_SLAB_FREELIST_RANDOM is not set
|
||||
CONFIG_SLAB_FREELIST_HARDENED=y
|
||||
@@ -957,7 +975,6 @@ CONFIG_SECRETMEM=y
|
||||
CONFIG_USERFAULTFD=y
|
||||
CONFIG_HAVE_ARCH_USERFAULTFD_WP=y
|
||||
CONFIG_HAVE_ARCH_USERFAULTFD_MINOR=y
|
||||
CONFIG_PTE_MARKER=y
|
||||
CONFIG_PTE_MARKER_UFFD_WP=y
|
||||
# CONFIG_LRU_GEN is not set
|
||||
|
||||
@@ -1122,7 +1139,6 @@ CONFIG_PCIE_PME=y
|
||||
# CONFIG_PCIE_DPC is not set
|
||||
# CONFIG_PCIE_PTM is not set
|
||||
CONFIG_PCI_MSI=y
|
||||
CONFIG_PCI_MSI_IRQ_DOMAIN=y
|
||||
CONFIG_PCI_QUIRKS=y
|
||||
CONFIG_PCI_DEBUG=y
|
||||
CONFIG_PCI_STUB=y
|
||||
@@ -1251,11 +1267,8 @@ CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
|
||||
# EFI (Extensible Firmware Interface) Support
|
||||
#
|
||||
CONFIG_EFI_ESRT=y
|
||||
CONFIG_EFI_RUNTIME_MAP=y
|
||||
# CONFIG_EFI_FAKE_MEMMAP is not set
|
||||
CONFIG_EFI_DXE_MEM_ATTRIBUTES=y
|
||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||
CONFIG_EFI_GENERIC_STUB_INITRD_CMDLINE_LOADER=y
|
||||
# CONFIG_EFI_BOOTLOADER_CONTROL is not set
|
||||
# CONFIG_EFI_CAPSULE_LOADER is not set
|
||||
# CONFIG_EFI_TEST is not set
|
||||
@@ -1296,6 +1309,7 @@ CONFIG_ZRAM_DEF_COMP_LZORLE=y
|
||||
CONFIG_ZRAM_DEF_COMP="lzo-rle"
|
||||
# CONFIG_ZRAM_WRITEBACK is not set
|
||||
# CONFIG_ZRAM_MEMORY_TRACKING is not set
|
||||
# CONFIG_ZRAM_MULTI_COMP is not set
|
||||
CONFIG_BLK_DEV_LOOP=y
|
||||
CONFIG_BLK_DEV_LOOP_MIN_COUNT=8
|
||||
# CONFIG_BLK_DEV_DRBD is not set
|
||||
@@ -1550,6 +1564,7 @@ CONFIG_HW_CONSOLE=y
|
||||
CONFIG_VT_HW_CONSOLE_BINDING=y
|
||||
CONFIG_UNIX98_PTYS=y
|
||||
# CONFIG_LEGACY_PTYS is not set
|
||||
# CONFIG_LEGACY_TIOCSTI is not set
|
||||
# CONFIG_LDISC_AUTOLOAD is not set
|
||||
|
||||
#
|
||||
@@ -1624,8 +1639,6 @@ CONFIG_HANGCHECK_TIMER=y
|
||||
# CONFIG_TCG_TPM is not set
|
||||
# CONFIG_TELCLOCK is not set
|
||||
# CONFIG_XILLYBUS is not set
|
||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||
# end of Character devices
|
||||
|
||||
#
|
||||
@@ -1674,6 +1687,7 @@ CONFIG_GPIOLIB_IRQCHIP=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_CDEV=y
|
||||
CONFIG_GPIO_CDEV_V1=y
|
||||
CONFIG_GPIO_IDIO_16=y
|
||||
|
||||
#
|
||||
# Memory mapped GPIO drivers
|
||||
@@ -1717,6 +1731,7 @@ CONFIG_GPIO_PCI_IDIO_16=y
|
||||
# Virtual GPIO drivers
|
||||
#
|
||||
# CONFIG_GPIO_AGGREGATOR is not set
|
||||
# CONFIG_GPIO_LATCH is not set
|
||||
# CONFIG_GPIO_MOCKUP is not set
|
||||
# CONFIG_GPIO_VIRTIO is not set
|
||||
# CONFIG_GPIO_SIM is not set
|
||||
@@ -1784,6 +1799,7 @@ CONFIG_WATCHDOG_OPEN_TIMEOUT=0
|
||||
# CONFIG_MAX63XX_WATCHDOG is not set
|
||||
# CONFIG_ACQUIRE_WDT is not set
|
||||
# CONFIG_ADVANTECH_WDT is not set
|
||||
# CONFIG_ADVANTECH_EC_WDT is not set
|
||||
# CONFIG_ALIM1535_WDT is not set
|
||||
# CONFIG_ALIM7101_WDT is not set
|
||||
# CONFIG_EBC_C384_WDT is not set
|
||||
@@ -2124,9 +2140,10 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
||||
# CONFIG_UIO_MF624 is not set
|
||||
# CONFIG_UIO_HV_GENERIC is not set
|
||||
CONFIG_VFIO=y
|
||||
CONFIG_VFIO_CONTAINER=y
|
||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
# CONFIG_VFIO_NOIOMMU is not set
|
||||
CONFIG_VFIO_VIRQFD=y
|
||||
CONFIG_VFIO_PCI_CORE=y
|
||||
CONFIG_VFIO_PCI_MMAP=y
|
||||
CONFIG_VFIO_PCI_INTX=y
|
||||
@@ -2202,6 +2219,7 @@ CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
|
||||
CONFIG_IOMMU_DMA=y
|
||||
# CONFIG_AMD_IOMMU is not set
|
||||
# CONFIG_INTEL_IOMMU is not set
|
||||
# CONFIG_IOMMUFD is not set
|
||||
# CONFIG_IRQ_REMAP is not set
|
||||
CONFIG_HYPERV_IOMMU=y
|
||||
CONFIG_VIRTIO_IOMMU=y
|
||||
@@ -2544,12 +2562,7 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
|
||||
#
|
||||
# Memory initialization
|
||||
#
|
||||
CONFIG_CC_HAS_AUTO_VAR_INIT_PATTERN=y
|
||||
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO_BARE=y
|
||||
CONFIG_CC_HAS_AUTO_VAR_INIT_ZERO=y
|
||||
# CONFIG_INIT_STACK_NONE is not set
|
||||
# CONFIG_INIT_STACK_ALL_PATTERN is not set
|
||||
CONFIG_INIT_STACK_ALL_ZERO=y
|
||||
CONFIG_INIT_STACK_NONE=y
|
||||
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
||||
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
||||
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
|
||||
@@ -2585,7 +2598,6 @@ CONFIG_CRYPTO_MANAGER2=y
|
||||
# CONFIG_CRYPTO_USER is not set
|
||||
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
|
||||
# CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is not set
|
||||
CONFIG_CRYPTO_GF128MUL=y
|
||||
CONFIG_CRYPTO_NULL=y
|
||||
CONFIG_CRYPTO_NULL2=y
|
||||
# CONFIG_CRYPTO_PCRYPT is not set
|
||||
@@ -2795,6 +2807,7 @@ CONFIG_ARCH_USE_SYM_ANNOTATIONS=y
|
||||
#
|
||||
CONFIG_CRYPTO_LIB_UTILS=y
|
||||
CONFIG_CRYPTO_LIB_AES=y
|
||||
CONFIG_CRYPTO_LIB_GF128MUL=y
|
||||
CONFIG_CRYPTO_LIB_BLAKE2S_GENERIC=y
|
||||
# CONFIG_CRYPTO_LIB_CHACHA is not set
|
||||
# CONFIG_CRYPTO_LIB_CURVE25519 is not set
|
||||
@@ -2882,6 +2895,7 @@ CONFIG_FONT_8x16=y
|
||||
CONFIG_SG_POOL=y
|
||||
CONFIG_ARCH_HAS_PMEM_API=y
|
||||
CONFIG_MEMREGION=y
|
||||
CONFIG_ARCH_HAS_CPU_CACHE_INVALIDATE_MEMREGION=y
|
||||
CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE=y
|
||||
CONFIG_ARCH_HAS_COPY_MC=y
|
||||
CONFIG_ARCH_STACKWALK=y
|
||||
@@ -2922,7 +2936,8 @@ CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
|
||||
# CONFIG_DEBUG_INFO_DWARF4 is not set
|
||||
# CONFIG_DEBUG_INFO_DWARF5 is not set
|
||||
# CONFIG_DEBUG_INFO_REDUCED is not set
|
||||
# CONFIG_DEBUG_INFO_COMPRESSED is not set
|
||||
CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
|
||||
# CONFIG_DEBUG_INFO_COMPRESSED_ZLIB is not set
|
||||
# CONFIG_DEBUG_INFO_SPLIT is not set
|
||||
# CONFIG_DEBUG_INFO_BTF is not set
|
||||
# CONFIG_GDB_SCRIPTS is not set
|
||||
@@ -3098,6 +3113,7 @@ CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||
CONFIG_HAVE_FENTRY=y
|
||||
CONFIG_HAVE_OBJTOOL_MCOUNT=y
|
||||
CONFIG_HAVE_OBJTOOL_NOP_MCOUNT=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_BUILDTIME_MCOUNT_SORT=y
|
||||
CONFIG_TRACING_SUPPORT=y
|
||||
@@ -3157,7 +3173,6 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_HEXDUMP is not set
|
||||
# CONFIG_STRING_SELFTEST is not set
|
||||
# CONFIG_TEST_STRING_HELPERS is not set
|
||||
# CONFIG_TEST_STRSCPY is not set
|
||||
# CONFIG_TEST_KSTRTOX is not set
|
||||
# CONFIG_TEST_PRINTF is not set
|
||||
# CONFIG_TEST_SCANF is not set
|
||||
@@ -3166,7 +3181,6 @@ CONFIG_RUNTIME_TESTING_MENU=y
|
||||
# CONFIG_TEST_XARRAY is not set
|
||||
# CONFIG_TEST_MAPLE_TREE is not set
|
||||
# CONFIG_TEST_RHASHTABLE is not set
|
||||
# CONFIG_TEST_SIPHASH is not set
|
||||
# CONFIG_TEST_IDA is not set
|
||||
# CONFIG_FIND_BIT_BENCHMARK is not set
|
||||
# CONFIG_TEST_FIRMWARE is not set
|
||||
|
||||
@@ -3,7 +3,7 @@ set -x
|
||||
|
||||
rm -f /tmp/ubuntu-cloudinit.img
|
||||
mkdosfs -n CIDATA -C /tmp/ubuntu-cloudinit.img 8192
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/network-config ::
|
||||
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 ::
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
CLI_NAME="Cloud Hypervisor"
|
||||
|
||||
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
||||
CTR_IMAGE_VERSION="20230123-0"
|
||||
CTR_IMAGE_TAG="ghcr.io/cloud-hypervisor/cloud-hypervisor"
|
||||
CTR_IMAGE_VERSION="20230620-0"
|
||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||
|
||||
DOCKER_RUNTIME="docker"
|
||||
@@ -172,7 +172,11 @@ process_volumes_args() {
|
||||
cmd_help() {
|
||||
echo ""
|
||||
echo "Cloud Hypervisor $(basename "$0")"
|
||||
echo "Usage: $(basename "$0") <command> [<command args>]"
|
||||
echo "Usage: $(basename "$0") [flags] <command> [<command args>]"
|
||||
echo ""
|
||||
echo "Available flags":
|
||||
echo ""
|
||||
echo " --local Set the container image version being used to \"local\"."
|
||||
echo ""
|
||||
echo "Available commands:"
|
||||
echo ""
|
||||
@@ -422,7 +426,7 @@ cmd_tests() {
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
dbus-run-session ./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
if [ "$integration_sgx" = true ]; then
|
||||
@@ -535,6 +539,7 @@ cmd_tests() {
|
||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||
--env USER="root" \
|
||||
--env CH_LIBC="${libc}" \
|
||||
--env RUST_BACKTRACE="${RUST_BACKTRACE}" \
|
||||
"$CTR_IMAGE" \
|
||||
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||
fi
|
||||
|
||||
@@ -225,8 +225,8 @@ fi
|
||||
|
||||
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
@@ -240,7 +240,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 and ovs-dpdk rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_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
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||
@@ -279,4 +281,12 @@ else
|
||||
exit $RES
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --features "dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
time cargo test "dbus_api::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -56,26 +56,8 @@ popd
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
time make bzImage -j `nproc`
|
||||
cp vmlinux $VMLINUX_IMAGE || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
build_custom_linux
|
||||
fi
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
@@ -89,7 +71,9 @@ fi
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
# Test ovs-dpdk relies on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_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
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
@@ -45,29 +45,7 @@ if [ $? -ne 0 ]; then
|
||||
fi
|
||||
popd
|
||||
|
||||
# Build custom kernel based on virtio-pmem and virtio-fs upstream patches
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
SRCDIR=$PWD
|
||||
pushd $WORKLOADS_DIR
|
||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-6.1.6" $LINUX_CUSTOM_DIR
|
||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
pushd $LINUX_CUSTOM_DIR
|
||||
time make bzImage -j `nproc`
|
||||
cp vmlinux $VMLINUX_IMAGE || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||
rm -rf $LINUX_CUSTOM_DIR
|
||||
fi
|
||||
build_custom_linux
|
||||
|
||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
|
||||
@@ -42,8 +42,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
@@ -7,14 +7,45 @@ source $(dirname "$0")/test-util.sh
|
||||
process_common_args "$@"
|
||||
|
||||
WORKLOADS_DIR="$HOME/workloads"
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
mkdir -p "$WORKLOADS_DIR"
|
||||
|
||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||
|
||||
FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/rust-hypervisor-firmware/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||
FW="$WORKLOADS_DIR/hypervisor-fw"
|
||||
if [ ! -f "$FW" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FW_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
|
||||
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time wget --quiet $FOCAL_OS_IMAGE_URL || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
FOCAL_OS_RAW_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.raw"
|
||||
FOCAL_OS_RAW_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_RAW_IMAGE_NAME"
|
||||
if [ ! -f "$FOCAL_OS_RAW_IMAGE" ]; then
|
||||
pushd $WORKLOADS_DIR
|
||||
time qemu-img convert -p -f qcow2 -O raw $FOCAL_OS_IMAGE_NAME $FOCAL_OS_RAW_IMAGE_NAME || exit 1
|
||||
popd
|
||||
fi
|
||||
|
||||
pushd $WORKLOADS_DIR
|
||||
sha1sum sha1sums-x86_64 --check --ignore-missing
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||
exit 1
|
||||
fi
|
||||
popd
|
||||
|
||||
VMLINUX_IMAGE="$WORKLOADS_DIR/vmlinux"
|
||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||
build_custom_linux
|
||||
fi
|
||||
build_custom_linux
|
||||
|
||||
BLK_IMAGE="$WORKLOADS_DIR/blk.img"
|
||||
MNT_DIR="mount_image"
|
||||
@@ -33,7 +64,7 @@ VFIO_DIR="$WORKLOADS_DIR/vfio"
|
||||
VFIO_DISK_IMAGE="$WORKLOADS_DIR/vfio.img"
|
||||
rm -rf $VFIO_DIR $VFIO_DISK_IMAGE
|
||||
mkdir -p $VFIO_DIR
|
||||
cp $FOCAL_OS_IMAGE $VFIO_DIR
|
||||
cp $FOCAL_OS_RAW_IMAGE $VFIO_DIR
|
||||
cp $FW $VFIO_DIR
|
||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||
|
||||
@@ -52,7 +83,9 @@ cp target/$BUILD_TARGET/release/cloud-hypervisor $VFIO_DIR
|
||||
cp target/$BUILD_TARGET/release/ch-remote $VFIO_DIR
|
||||
|
||||
# test_vfio rely on hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_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
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
|
||||
@@ -24,8 +24,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
export TARGET_CC="musl-gcc"
|
||||
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -26,8 +26,8 @@ BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||
CFLAGS=""
|
||||
TARGET_CC=""
|
||||
if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
TARGET_CC="musl-gcc"
|
||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||
fi
|
||||
|
||||
# Check if the images are present
|
||||
|
||||
@@ -169,7 +169,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
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_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
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
# Update max locked memory to 'unlimited' to avoid issues with vDPA
|
||||
@@ -187,4 +189,13 @@ if [ $RES -eq 0 ]; then
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
# Run tests on dbus_api
|
||||
if [ $RES -eq 0 ]; then
|
||||
cargo build --no-default-features --features "kvm,mshv,dbus_api" --all --release --target $BUILD_TARGET
|
||||
export RUST_BACKTRACE=1
|
||||
# integration tests now do not reply on build feature "dbus_api"
|
||||
time cargo test $test_features "dbus_api::$test_filter" -- ${test_binary_args[*]}
|
||||
RES=$?
|
||||
fi
|
||||
|
||||
exit $RES
|
||||
|
||||
@@ -95,7 +95,9 @@ fi
|
||||
cargo build --no-default-features --features "kvm,mshv" --all --release --target $BUILD_TARGET
|
||||
|
||||
# setup hugepages
|
||||
echo 6144 | sudo tee /proc/sys/vm/nr_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
|
||||
sudo chmod a+rwX /dev/hugepages
|
||||
|
||||
if [ -n "$test_filter" ]; then
|
||||
@@ -105,7 +107,12 @@ fi
|
||||
# Ensure that git commands can be run in this directory (for metrics report)
|
||||
git config --global --add safe.directory $PWD
|
||||
|
||||
export RUST_BACKTRACE=1
|
||||
RUST_BACKTRACE_VALUE=`echo $RUST_BACKTRACE`
|
||||
if [ -z $RUST_BACKTRACE_VALUE ];then
|
||||
export RUST_BACKTRACE=1
|
||||
else
|
||||
echo "RUST_BACKTRACE is set to: $RUST_BACKTRACE_VALUE"
|
||||
fi
|
||||
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||
RES=$?
|
||||
|
||||
|
||||
@@ -22,3 +22,4 @@ 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
|
||||
|
||||
@@ -3,4 +3,3 @@ f1eccdc5e1b515dbad294426ab081b47ebfb97c0 focal-server-cloudimg-amd64-custom-2021
|
||||
7f5a8358243a96adf61f5c20139b29f308f2c0e3 focal-server-cloudimg-amd64-custom-20210609-0.raw
|
||||
864c074e2f1bd753667a35188b510d83a1d62793 jammy-server-cloudimg-amd64-custom-20230119-0.qcow2
|
||||
24358ee053f94e7f710ea4ce9e7a63eff2a1eb25 jammy-server-cloudimg-amd64-custom-20230119-0.raw
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ build_custom_linux() {
|
||||
ARCH=$(uname -m)
|
||||
SRCDIR=$PWD
|
||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||
LINUX_CUSTOM_BRANCH="ch-6.1.6"
|
||||
LINUX_CUSTOM_BRANCH="ch-6.2"
|
||||
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
||||
|
||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||
|
||||
@@ -11,13 +11,19 @@ use argh::FromArgs;
|
||||
use option_parser::{ByteSized, ByteSizedParseError};
|
||||
use std::fmt;
|
||||
use std::io::Read;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::process;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use zbus::{dbus_proxy, zvariant::Optional};
|
||||
|
||||
type ApiResult = Result<(), Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Error {
|
||||
Connect(std::io::Error),
|
||||
ApiClient(ApiClientError),
|
||||
HttpApiClient(ApiClientError),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApiClient(zbus::Error),
|
||||
InvalidMemorySize(ByteSizedParseError),
|
||||
InvalidBalloonSize(ByteSizedParseError),
|
||||
AddDeviceConfig(vmm::config::Error),
|
||||
@@ -37,8 +43,9 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Error::*;
|
||||
match self {
|
||||
ApiClient(e) => e.fmt(f),
|
||||
Connect(e) => write!(f, "Error opening HTTP socket: {e}"),
|
||||
HttpApiClient(e) => e.fmt(f),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApiClient(e) => write!(f, "Error D-Bus proxy: {e}"),
|
||||
InvalidMemorySize(e) => write!(f, "Error parsing memory size: {e:?}"),
|
||||
InvalidBalloonSize(e) => write!(f, "Error parsing balloon size: {e:?}"),
|
||||
AddDeviceConfig(e) => write!(f, "Error parsing device syntax: {e}"),
|
||||
@@ -56,12 +63,430 @@ impl fmt::Display for Error {
|
||||
}
|
||||
}
|
||||
|
||||
fn resize_api_command(
|
||||
socket: &mut UnixStream,
|
||||
enum TargetApi<'a> {
|
||||
HttpApi(UnixStream, PhantomData<&'a ()>),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
DBusApi(DBusApi1ProxyBlocking<'a>),
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[dbus_proxy(name = "org.cloudhypervisor.DBusApi1", assume_defaults = false)]
|
||||
trait DBusApi1 {
|
||||
fn vmm_ping(&self) -> zbus::Result<String>;
|
||||
fn vmm_shutdown(&self) -> zbus::Result<()>;
|
||||
fn vm_add_device(&self, device_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_disk(&self, disk_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_fs(&self, fs_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_net(&self, net_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_pmem(&self, pmem_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_user_device(&self, vm_add_user_device: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_vdpa(&self, vdpa_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_add_vsock(&self, vsock_config: &str) -> zbus::Result<Optional<String>>;
|
||||
fn vm_boot(&self) -> zbus::Result<()>;
|
||||
fn vm_coredump(&self, vm_coredump_data: &str) -> zbus::Result<()>;
|
||||
fn vm_counters(&self) -> zbus::Result<Optional<String>>;
|
||||
fn vm_create(&self, vm_config: &str) -> zbus::Result<()>;
|
||||
fn vm_delete(&self) -> zbus::Result<()>;
|
||||
fn vm_info(&self) -> zbus::Result<String>;
|
||||
fn vm_pause(&self) -> zbus::Result<()>;
|
||||
fn vm_power_button(&self) -> zbus::Result<()>;
|
||||
fn vm_reboot(&self) -> zbus::Result<()>;
|
||||
fn vm_remove_device(&self, vm_remove_device: &str) -> zbus::Result<()>;
|
||||
fn vm_resize(&self, vm_resize: &str) -> zbus::Result<()>;
|
||||
fn vm_resize_zone(&self, vm_resize_zone: &str) -> zbus::Result<()>;
|
||||
fn vm_restore(&self, restore_config: &str) -> zbus::Result<()>;
|
||||
fn vm_receive_migration(&self, receive_migration_data: &str) -> zbus::Result<()>;
|
||||
fn vm_send_migration(&self, receive_migration_data: &str) -> zbus::Result<()>;
|
||||
fn vm_resume(&self) -> zbus::Result<()>;
|
||||
fn vm_shutdown(&self) -> zbus::Result<()>;
|
||||
fn vm_snapshot(&self, vm_snapshot_config: &str) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
impl<'a> DBusApi1ProxyBlocking<'a> {
|
||||
fn new_connection(name: &'a str, path: &'a str, system_bus: bool) -> Result<Self, zbus::Error> {
|
||||
let connection = if system_bus {
|
||||
zbus::blocking::Connection::system()?
|
||||
} else {
|
||||
zbus::blocking::Connection::session()?
|
||||
};
|
||||
|
||||
Self::builder(&connection)
|
||||
.destination(name)?
|
||||
.path(path)?
|
||||
.build()
|
||||
}
|
||||
|
||||
fn print_response(&self, result: zbus::Result<Optional<String>>) -> ApiResult {
|
||||
result
|
||||
.map(|ret| {
|
||||
if let Some(ref output) = *ret {
|
||||
println!("{output}");
|
||||
}
|
||||
})
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vmm_ping(&self) -> ApiResult {
|
||||
self.vmm_ping()
|
||||
.map(|ping| println!("{ping}"))
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vmm_shutdown(&self) -> ApiResult {
|
||||
self.vmm_shutdown().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_add_device(&self, device_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_device(device_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_disk(&self, disk_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_disk(disk_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_fs(&self, fs_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_fs(fs_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_net(&self, net_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_net(net_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_pmem(&self, pmem_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_pmem(pmem_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_user_device(&self, vm_add_user_device: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_user_device(vm_add_user_device))
|
||||
}
|
||||
|
||||
fn api_vm_add_vdpa(&self, vdpa_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_vdpa(vdpa_config))
|
||||
}
|
||||
|
||||
fn api_vm_add_vsock(&self, vsock_config: &str) -> ApiResult {
|
||||
self.print_response(self.vm_add_vsock(vsock_config))
|
||||
}
|
||||
|
||||
fn api_vm_boot(&self) -> ApiResult {
|
||||
self.vm_boot().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_coredump(&self, vm_coredump_data: &str) -> ApiResult {
|
||||
self.vm_coredump(vm_coredump_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_counters(&self) -> ApiResult {
|
||||
self.print_response(self.vm_counters())
|
||||
}
|
||||
|
||||
fn api_vm_create(&self, vm_config: &str) -> ApiResult {
|
||||
self.vm_create(vm_config).map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_delete(&self) -> ApiResult {
|
||||
self.vm_delete().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_info(&self) -> ApiResult {
|
||||
self.vm_info()
|
||||
.map(|info| println!("{info}"))
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_pause(&self) -> ApiResult {
|
||||
self.vm_pause().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_power_button(&self) -> ApiResult {
|
||||
self.vm_power_button().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_reboot(&self) -> ApiResult {
|
||||
self.vm_reboot().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_remove_device(&self, vm_remove_device: &str) -> ApiResult {
|
||||
self.vm_remove_device(vm_remove_device)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resize(&self, vm_resize: &str) -> ApiResult {
|
||||
self.vm_resize(vm_resize).map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resize_zone(&self, vm_resize_zone: &str) -> ApiResult {
|
||||
self.vm_resize_zone(vm_resize_zone)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_restore(&self, restore_config: &str) -> ApiResult {
|
||||
self.vm_restore(restore_config)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_receive_migration(&self, receive_migration_data: &str) -> ApiResult {
|
||||
self.vm_receive_migration(receive_migration_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_send_migration(&self, send_migration_data: &str) -> ApiResult {
|
||||
self.vm_send_migration(send_migration_data)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_resume(&self) -> ApiResult {
|
||||
self.vm_resume().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_shutdown(&self) -> ApiResult {
|
||||
self.vm_shutdown().map_err(Error::DBusApiClient)
|
||||
}
|
||||
|
||||
fn api_vm_snapshot(&self, vm_snapshot_config: &str) -> ApiResult {
|
||||
self.vm_snapshot(vm_snapshot_config)
|
||||
.map_err(Error::DBusApiClient)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TargetApi<'a> {
|
||||
fn do_command(&mut self, toplevel: &TopLevel) -> ApiResult {
|
||||
match self {
|
||||
Self::HttpApi(api_socket, _) => rest_api_do_command(toplevel, api_socket),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
Self::DBusApi(proxy) => dbus_api_do_command(toplevel, proxy),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn rest_api_do_command(toplevel: &TopLevel, socket: &mut UnixStream) -> ApiResult {
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => {
|
||||
simple_api_command(socket, "PUT", "boot", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Delete(_) => {
|
||||
simple_api_command(socket, "PUT", "delete", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ShutdownVmm(_) => {
|
||||
simple_api_full_command(socket, "PUT", "vmm.shutdown", None)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Resume(_) => {
|
||||
simple_api_command(socket, "PUT", "resume", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::PowerButton(_) => {
|
||||
simple_api_command(socket, "PUT", "power-button", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Reboot(_) => {
|
||||
simple_api_command(socket, "PUT", "reboot", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Pause(_) => {
|
||||
simple_api_command(socket, "PUT", "pause", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Info(_) => {
|
||||
simple_api_command(socket, "GET", "info", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Counters(_) => {
|
||||
simple_api_command(socket, "GET", "counters", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Ping(_) => {
|
||||
simple_api_full_command(socket, "GET", "vmm.ping", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Shutdown(_) => {
|
||||
simple_api_command(socket, "PUT", "shutdown", None).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
let resize = resize_config(config.cpus, &config.memory, &config.balloon)?;
|
||||
simple_api_command(socket, "PUT", "resize", Some(&resize)).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
let resize_zone = resize_zone_config(&config.id, &config.size)?;
|
||||
simple_api_command(socket, "PUT", "resize-zone", Some(&resize_zone))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
let device_config = add_device_config(&config.device_config)?;
|
||||
simple_api_command(socket, "PUT", "add-device", Some(&device_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
let remove_device_data = remove_device_config(&config.device_config);
|
||||
simple_api_command(socket, "PUT", "remove-device", Some(&remove_device_data))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
let disk_config = add_disk_config(&config.disk_config)?;
|
||||
simple_api_command(socket, "PUT", "add-disk", Some(&disk_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => {
|
||||
let fs_config = add_fs_config(&config.fs_config)?;
|
||||
simple_api_command(socket, "PUT", "add-fs", Some(&fs_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
let pmem_config = add_pmem_config(&config.pmem_config)?;
|
||||
simple_api_command(socket, "PUT", "add-pmem", Some(&pmem_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => {
|
||||
let (net_config, fds) = add_net_config(&config.net_config)?;
|
||||
simple_api_command_with_fds(socket, "PUT", "add-net", Some(&net_config), fds)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
let device_config = add_user_device_config(&config.device_config)?;
|
||||
simple_api_command(socket, "PUT", "add-user-device", Some(&device_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
let vdpa_config = add_vdpa_config(&config.vdpa_config)?;
|
||||
simple_api_command(socket, "PUT", "add-vdpa", Some(&vdpa_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
let vsock_config = add_vsock_config(&config.vsock_config)?;
|
||||
simple_api_command(socket, "PUT", "add-vsock", Some(&vsock_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
let snapshot_config = snapshot_api_config(&config.snapshot_config);
|
||||
simple_api_command(socket, "PUT", "snapshot", Some(&snapshot_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
let restore_config = restore_config(&config.restore_config)?;
|
||||
simple_api_command(socket, "PUT", "restore", Some(&restore_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
let coredump_config = coredump_config(&config.coredump_config);
|
||||
simple_api_command(socket, "PUT", "coredump", Some(&coredump_config))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => {
|
||||
let send_migration_data =
|
||||
send_migration_data(&config.send_migration_config, config.send_migration_local);
|
||||
simple_api_command(socket, "PUT", "send-migration", Some(&send_migration_data))
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
let receive_migration_data = receive_migration_data(&config.receive_migration_config);
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"receive-migration",
|
||||
Some(&receive_migration_data),
|
||||
)
|
||||
.map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => {
|
||||
let data = create_data(&config.vm_config)?;
|
||||
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::HttpApiClient)
|
||||
}
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
fn dbus_api_do_command(toplevel: &TopLevel, proxy: &mut DBusApi1ProxyBlocking<'_>) -> ApiResult {
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => proxy.api_vm_boot(),
|
||||
SubCommandEnum::Delete(_) => proxy.api_vm_delete(),
|
||||
SubCommandEnum::ShutdownVmm(_) => proxy.api_vmm_shutdown(),
|
||||
SubCommandEnum::Resume(_) => proxy.api_vm_resume(),
|
||||
SubCommandEnum::PowerButton(_) => proxy.api_vm_power_button(),
|
||||
SubCommandEnum::Reboot(_) => proxy.api_vm_reboot(),
|
||||
SubCommandEnum::Pause(_) => proxy.api_vm_pause(),
|
||||
SubCommandEnum::Info(_) => proxy.api_vm_info(),
|
||||
SubCommandEnum::Counters(_) => proxy.api_vm_counters(),
|
||||
SubCommandEnum::Ping(_) => proxy.api_vmm_ping(),
|
||||
SubCommandEnum::Shutdown(_) => proxy.api_vm_shutdown(),
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
let resize = resize_config(config.cpus, &config.memory, &config.balloon)?;
|
||||
proxy.api_vm_resize(&resize)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
let resize_zone = resize_zone_config(&config.id, &config.size)?;
|
||||
proxy.api_vm_resize_zone(&resize_zone)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
let device_config = add_device_config(&config.device_config)?;
|
||||
proxy.api_vm_add_device(&device_config)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
let remove_device_data = remove_device_config(&config.device_config);
|
||||
proxy.api_vm_remove_device(&remove_device_data)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
let disk_config = add_disk_config(&config.disk_config)?;
|
||||
proxy.api_vm_add_disk(&disk_config)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => {
|
||||
let fs_config = add_fs_config(&config.fs_config)?;
|
||||
proxy.api_vm_add_fs(&fs_config)
|
||||
}
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
let pmem_config = add_pmem_config(&config.pmem_config)?;
|
||||
proxy.api_vm_add_pmem(&pmem_config)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => {
|
||||
let (net_config, _fds) = add_net_config(&config.net_config)?;
|
||||
proxy.api_vm_add_net(&net_config)
|
||||
}
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
let device_config = add_user_device_config(&config.device_config)?;
|
||||
proxy.api_vm_add_user_device(&device_config)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
let vdpa_config = add_vdpa_config(&config.vdpa_config)?;
|
||||
proxy.api_vm_add_vdpa(&vdpa_config)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
let vsock_config = add_vsock_config(&config.vsock_config)?;
|
||||
proxy.api_vm_add_vsock(&vsock_config)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
let snapshot_config = snapshot_api_config(&config.snapshot_config);
|
||||
proxy.api_vm_snapshot(&snapshot_config)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
let restore_config = restore_config(&config.restore_config)?;
|
||||
proxy.api_vm_restore(&restore_config)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
let coredump_config = coredump_config(&config.coredump_config);
|
||||
proxy.api_vm_coredump(&coredump_config)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => {
|
||||
let send_migration_data =
|
||||
send_migration_data(&config.send_migration_config, config.send_migration_local);
|
||||
proxy.api_vm_send_migration(&send_migration_data)
|
||||
}
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
let receive_migration_data = receive_migration_data(&config.receive_migration_config);
|
||||
proxy.api_vm_receive_migration(&receive_migration_data)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => {
|
||||
let data = create_data(&config.vm_config)?;
|
||||
proxy.api_vm_create(&data)
|
||||
}
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
}
|
||||
fn resize_config(
|
||||
desired_vcpus: Option<u8>,
|
||||
memory: &Option<String>,
|
||||
balloon: &Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<String, Error> {
|
||||
let desired_ram: Option<u64> = if let Some(memory) = memory {
|
||||
Some(
|
||||
memory
|
||||
@@ -90,16 +515,10 @@ fn resize_api_command(
|
||||
desired_balloon,
|
||||
};
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"resize",
|
||||
Some(&serde_json::to_string(&resize).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(serde_json::to_string(&resize).unwrap())
|
||||
}
|
||||
|
||||
fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Result<(), Error> {
|
||||
fn resize_zone_config(id: &str, size: &str) -> Result<String, Error> {
|
||||
let resize_zone = vmm::api::VmResizeZoneData {
|
||||
id: id.to_owned(),
|
||||
desired_ram: size
|
||||
@@ -108,89 +527,52 @@ fn resize_zone_api_command(socket: &mut UnixStream, id: &str, size: &str) -> Res
|
||||
.0,
|
||||
};
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"resize-zone",
|
||||
Some(&serde_json::to_string(&resize_zone).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(serde_json::to_string(&resize_zone).unwrap())
|
||||
}
|
||||
|
||||
fn add_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_device_config(config: &str) -> Result<String, Error> {
|
||||
let device_config = vmm::config::DeviceConfig::parse(config).map_err(Error::AddDeviceConfig)?;
|
||||
let device_config = serde_json::to_string(&device_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-device",
|
||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(device_config)
|
||||
}
|
||||
|
||||
fn add_user_device_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_user_device_config(config: &str) -> Result<String, Error> {
|
||||
let device_config =
|
||||
vmm::config::UserDeviceConfig::parse(config).map_err(Error::AddUserDeviceConfig)?;
|
||||
let device_config = serde_json::to_string(&device_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-user-device",
|
||||
Some(&serde_json::to_string(&device_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(device_config)
|
||||
}
|
||||
|
||||
fn remove_device_api_command(socket: &mut UnixStream, id: &str) -> Result<(), Error> {
|
||||
fn remove_device_config(id: &str) -> String {
|
||||
let remove_device_data = vmm::api::VmRemoveDeviceData { id: id.to_owned() };
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"remove-device",
|
||||
Some(&serde_json::to_string(&remove_device_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
serde_json::to_string(&remove_device_data).unwrap()
|
||||
}
|
||||
|
||||
fn add_disk_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_disk_config(config: &str) -> Result<String, Error> {
|
||||
let disk_config = vmm::config::DiskConfig::parse(config).map_err(Error::AddDiskConfig)?;
|
||||
let disk_config = serde_json::to_string(&disk_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-disk",
|
||||
Some(&serde_json::to_string(&disk_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(disk_config)
|
||||
}
|
||||
|
||||
fn add_fs_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_fs_config(config: &str) -> Result<String, Error> {
|
||||
let fs_config = vmm::config::FsConfig::parse(config).map_err(Error::AddFsConfig)?;
|
||||
let fs_config = serde_json::to_string(&fs_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-fs",
|
||||
Some(&serde_json::to_string(&fs_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(fs_config)
|
||||
}
|
||||
|
||||
fn add_pmem_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_pmem_config(config: &str) -> Result<String, Error> {
|
||||
let pmem_config = vmm::config::PmemConfig::parse(config).map_err(Error::AddPmemConfig)?;
|
||||
let pmem_config = serde_json::to_string(&pmem_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-pmem",
|
||||
Some(&serde_json::to_string(&pmem_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(pmem_config)
|
||||
}
|
||||
|
||||
fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_net_config(config: &str) -> Result<(String, Vec<i32>), Error> {
|
||||
let mut net_config = vmm::config::NetConfig::parse(config).map_err(Error::AddNetConfig)?;
|
||||
|
||||
// NetConfig is modified on purpose here by taking the list of file
|
||||
@@ -198,113 +580,66 @@ fn add_net_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Erro
|
||||
// process would not make any sense since the file descriptor may be
|
||||
// represented with different values.
|
||||
let fds = net_config.fds.take().unwrap_or_default();
|
||||
let net_config = serde_json::to_string(&net_config).unwrap();
|
||||
|
||||
simple_api_command_with_fds(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-net",
|
||||
Some(&serde_json::to_string(&net_config).unwrap()),
|
||||
fds,
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok((net_config, fds))
|
||||
}
|
||||
|
||||
fn add_vdpa_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_vdpa_config(config: &str) -> Result<String, Error> {
|
||||
let vdpa_config = vmm::config::VdpaConfig::parse(config).map_err(Error::AddVdpaConfig)?;
|
||||
let vdpa_config = serde_json::to_string(&vdpa_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-vdpa",
|
||||
Some(&serde_json::to_string(&vdpa_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(vdpa_config)
|
||||
}
|
||||
|
||||
fn add_vsock_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn add_vsock_config(config: &str) -> Result<String, Error> {
|
||||
let vsock_config = vmm::config::VsockConfig::parse(config).map_err(Error::AddVsockConfig)?;
|
||||
let vsock_config = serde_json::to_string(&vsock_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"add-vsock",
|
||||
Some(&serde_json::to_string(&vsock_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(vsock_config)
|
||||
}
|
||||
|
||||
fn snapshot_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||
fn snapshot_api_config(url: &str) -> String {
|
||||
let snapshot_config = vmm::api::VmSnapshotConfig {
|
||||
destination_url: String::from(url),
|
||||
};
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"snapshot",
|
||||
Some(&serde_json::to_string(&snapshot_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
serde_json::to_string(&snapshot_config).unwrap()
|
||||
}
|
||||
|
||||
fn restore_api_command(socket: &mut UnixStream, config: &str) -> Result<(), Error> {
|
||||
fn restore_config(config: &str) -> Result<String, Error> {
|
||||
let restore_config = vmm::config::RestoreConfig::parse(config).map_err(Error::Restore)?;
|
||||
let restore_config = serde_json::to_string(&restore_config).unwrap();
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"restore",
|
||||
Some(&serde_json::to_string(&restore_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
Ok(restore_config)
|
||||
}
|
||||
|
||||
fn coredump_api_command(socket: &mut UnixStream, destination_url: &str) -> Result<(), Error> {
|
||||
fn coredump_config(destination_url: &str) -> String {
|
||||
let coredump_config = vmm::api::VmCoredumpData {
|
||||
destination_url: String::from(destination_url),
|
||||
};
|
||||
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"coredump",
|
||||
Some(&serde_json::to_string(&coredump_config).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
serde_json::to_string(&coredump_config).unwrap()
|
||||
}
|
||||
|
||||
fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
||||
fn receive_migration_data(url: &str) -> String {
|
||||
let receive_migration_data = vmm::api::VmReceiveMigrationData {
|
||||
receiver_url: url.to_owned(),
|
||||
};
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"receive-migration",
|
||||
Some(&serde_json::to_string(&receive_migration_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
|
||||
serde_json::to_string(&receive_migration_data).unwrap()
|
||||
}
|
||||
|
||||
fn send_migration_api_command(
|
||||
socket: &mut UnixStream,
|
||||
url: &str,
|
||||
local: bool,
|
||||
) -> Result<(), Error> {
|
||||
fn send_migration_data(url: &str, local: bool) -> String {
|
||||
let send_migration_data = vmm::api::VmSendMigrationData {
|
||||
destination_url: url.to_owned(),
|
||||
local,
|
||||
};
|
||||
simple_api_command(
|
||||
socket,
|
||||
"PUT",
|
||||
"send-migration",
|
||||
Some(&serde_json::to_string(&send_migration_data).unwrap()),
|
||||
)
|
||||
.map_err(Error::ApiClient)
|
||||
|
||||
serde_json::to_string(&send_migration_data).unwrap()
|
||||
}
|
||||
|
||||
fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error> {
|
||||
fn create_data(path: &str) -> Result<String, Error> {
|
||||
let mut data = String::default();
|
||||
if path == "-" {
|
||||
std::io::stdin()
|
||||
@@ -314,100 +649,7 @@ fn create_api_command(socket: &mut UnixStream, path: &str) -> Result<(), Error>
|
||||
data = std::fs::read_to_string(path).map_err(Error::ReadingFile)?;
|
||||
}
|
||||
|
||||
simple_api_command(socket, "PUT", "create", Some(&data)).map_err(Error::ApiClient)
|
||||
}
|
||||
|
||||
fn do_command(toplevel: &TopLevel) -> Result<(), Error> {
|
||||
let mut socket =
|
||||
UnixStream::connect(toplevel.api_socket.as_deref().unwrap()).map_err(Error::Connect)?;
|
||||
|
||||
match toplevel.command {
|
||||
SubCommandEnum::Boot(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "boot", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Delete(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "delete", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::ShutdownVmm(_) => {
|
||||
simple_api_full_command(&mut socket, "PUT", "vmm.shutdown", None)
|
||||
.map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Resume(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "resume", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::PowerButton(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "power-button", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Reboot(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "reboot", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Pause(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "pause", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Info(_) => {
|
||||
simple_api_command(&mut socket, "GET", "info", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Counters(_) => {
|
||||
simple_api_command(&mut socket, "GET", "counters", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Ping(_) => {
|
||||
simple_api_full_command(&mut socket, "GET", "vmm.ping", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Shutdown(_) => {
|
||||
simple_api_command(&mut socket, "PUT", "shutdown", None).map_err(Error::ApiClient)
|
||||
}
|
||||
SubCommandEnum::Resize(ref config) => {
|
||||
resize_api_command(&mut socket, config.cpus, &config.memory, &config.balloon)
|
||||
}
|
||||
SubCommandEnum::ResizeZone(ref config) => {
|
||||
resize_zone_api_command(&mut socket, &config.id, &config.size)
|
||||
}
|
||||
SubCommandEnum::AddDevice(ref config) => {
|
||||
add_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::RemoveDevice(ref config) => {
|
||||
remove_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::AddDisk(ref config) => {
|
||||
add_disk_api_command(&mut socket, &config.disk_config)
|
||||
}
|
||||
SubCommandEnum::AddFs(ref config) => add_fs_api_command(&mut socket, &config.fs_config),
|
||||
SubCommandEnum::AddPmem(ref config) => {
|
||||
add_pmem_api_command(&mut socket, &config.pmem_config)
|
||||
}
|
||||
SubCommandEnum::AddNet(ref config) => add_net_api_command(&mut socket, &config.net_config),
|
||||
SubCommandEnum::AddUserDevice(ref config) => {
|
||||
add_user_device_api_command(&mut socket, &config.device_config)
|
||||
}
|
||||
SubCommandEnum::AddVdpa(ref config) => {
|
||||
add_vdpa_api_command(&mut socket, &config.vdpa_config)
|
||||
}
|
||||
SubCommandEnum::AddVsock(ref config) => {
|
||||
add_vsock_api_command(&mut socket, &config.vsock_config)
|
||||
}
|
||||
SubCommandEnum::Snapshot(ref config) => {
|
||||
snapshot_api_command(&mut socket, &config.snapshot_config)
|
||||
}
|
||||
SubCommandEnum::Restore(ref config) => {
|
||||
restore_api_command(&mut socket, &config.restore_config)
|
||||
}
|
||||
SubCommandEnum::Coredump(ref config) => {
|
||||
coredump_api_command(&mut socket, &config.coredump_config)
|
||||
}
|
||||
SubCommandEnum::SendMigration(ref config) => send_migration_api_command(
|
||||
&mut socket,
|
||||
&config.send_migration_config,
|
||||
config.send_migration_local,
|
||||
),
|
||||
SubCommandEnum::ReceiveMigration(ref config) => {
|
||||
receive_migration_api_command(&mut socket, &config.receive_migration_config)
|
||||
}
|
||||
SubCommandEnum::Create(ref config) => create_api_command(&mut socket, &config.vm_config),
|
||||
SubCommandEnum::Version(_) => {
|
||||
// Already handled outside of this function
|
||||
panic!()
|
||||
}
|
||||
}
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
@@ -419,6 +661,21 @@ struct TopLevel {
|
||||
#[argh(option, long = "api-socket")]
|
||||
/// HTTP API socket path (UNIX domain socket)
|
||||
api_socket: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-service-name")]
|
||||
/// well known name of the dbus service
|
||||
dbus_name: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-object-path")]
|
||||
/// object path which the interface is being served at
|
||||
dbus_path: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(switch, long = "dbus-system-bus")]
|
||||
/// use the system bus instead of a session bus
|
||||
dbus_system_bus: bool,
|
||||
}
|
||||
|
||||
#[derive(FromArgs, PartialEq, Debug)]
|
||||
@@ -688,16 +945,56 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if matches!(toplevel.command, SubCommandEnum::Version(_)) {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
if toplevel.api_socket.is_none() {
|
||||
println!("Please specify --api-socket");
|
||||
process::exit(1)
|
||||
}
|
||||
let mut target_api = match (
|
||||
&toplevel.api_socket,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
&toplevel.dbus_name,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
&toplevel.dbus_path,
|
||||
) {
|
||||
#[cfg(not(feature = "dbus_api"))]
|
||||
(Some(ref api_socket),) => TargetApi::HttpApi(
|
||||
UnixStream::connect(api_socket).unwrap_or_else(|e| {
|
||||
eprintln!("Error opening HTTP socket: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
PhantomData,
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(Some(ref api_socket), None, None) => TargetApi::HttpApi(
|
||||
UnixStream::connect(api_socket).unwrap_or_else(|e| {
|
||||
eprintln!("Error opening HTTP socket: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
PhantomData,
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(None, Some(ref dbus_name), Some(ref dbus_path)) => TargetApi::DBusApi(
|
||||
DBusApi1ProxyBlocking::new_connection(dbus_name, dbus_path, toplevel.dbus_system_bus)
|
||||
.map_err(Error::DBusApiClient)
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("Error creating D-Bus proxy: {e}");
|
||||
process::exit(1)
|
||||
}),
|
||||
),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
(Some(_), Some(_) | None, Some(_) | None) => {
|
||||
println!(
|
||||
"`api-socket` and (dbus-service-name or dbus-object-path) are mutually exclusive"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
_ => {
|
||||
println!("Please either provide the api-socket option or dbus-service-name and dbus-object-path options");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = do_command(&toplevel) {
|
||||
if let Err(e) = target_api.do_command(&toplevel) {
|
||||
eprintln!("Error running command: {e}");
|
||||
process::exit(1)
|
||||
};
|
||||
|
||||
160
src/main.rs
160
src/main.rs
@@ -8,7 +8,7 @@ extern crate event_monitor;
|
||||
|
||||
use argh::FromArgs;
|
||||
use libc::EFD_NONBLOCK;
|
||||
use log::LevelFilter;
|
||||
use log::{warn, LevelFilter};
|
||||
use option_parser::OptionParser;
|
||||
use seccompiler::SeccompAction;
|
||||
use signal_hook::consts::SIGSYS;
|
||||
@@ -18,6 +18,8 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "dbus_api")]
|
||||
use vmm::api::dbus::{dbus_api_graceful_shutdown, DBusApiOptions};
|
||||
use vmm::config;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::block_signal;
|
||||
@@ -33,6 +35,8 @@ enum Error {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
#[error("Failed to create Debug EventFd: {0}")]
|
||||
CreateDebugEventFd(#[source] std::io::Error),
|
||||
#[error("Failed to create exit EventFd: {0}")]
|
||||
CreateExitEventFd(#[source] std::io::Error),
|
||||
#[error("Failed to open hypervisor interface (is hypervisor interface available?): {0}")]
|
||||
CreateHypervisor(#[source] hypervisor::HypervisorError),
|
||||
#[error("Failed to start the VMM thread: {0}")]
|
||||
@@ -55,6 +59,12 @@ enum Error {
|
||||
ParsingApiSocket(std::num::ParseIntError),
|
||||
#[error("Error parsing --event-monitor: {0}")]
|
||||
ParsingEventMonitor(option_parser::OptionParserError),
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-object-path` option isn't provided")]
|
||||
MissingDBusObjectPath,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[error("`--dbus-service-name` option isn't provided")]
|
||||
MissingDBusServiceName,
|
||||
#[error("Error parsing --event-monitor: path or fd required")]
|
||||
BareEventMonitor,
|
||||
#[error("Error doing event monitor I/O: {0}")]
|
||||
@@ -90,9 +100,9 @@ impl log::Log for Logger {
|
||||
let duration = now.duration_since(self.start);
|
||||
|
||||
if record.file().is_some() && record.line().is_some() {
|
||||
writeln!(
|
||||
write!(
|
||||
*(*(self.output.lock().unwrap())),
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}",
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{}:{} -- {}\r\n",
|
||||
duration,
|
||||
std::thread::current().name().unwrap_or("anonymous"),
|
||||
record.level(),
|
||||
@@ -101,9 +111,9 @@ impl log::Log for Logger {
|
||||
record.args()
|
||||
)
|
||||
} else {
|
||||
writeln!(
|
||||
write!(
|
||||
*(*(self.output.lock().unwrap())),
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}",
|
||||
"cloud-hypervisor: {:.6?}: <{}> {}:{} -- {}\r\n",
|
||||
duration,
|
||||
std::thread::current().name().unwrap_or("anonymous"),
|
||||
record.level(),
|
||||
@@ -136,19 +146,19 @@ fn default_rng() -> String {
|
||||
/// Launch a cloud-hypervisor VMM.
|
||||
pub struct TopLevel {
|
||||
#[argh(option, long = "cpus", default = "default_vcpus()")]
|
||||
/// boot=<boot_vcpus>,max=<max_vcpus>,topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>,kvm_hyperv=on|off,max_phys_bits=<maximum_number_of_physical_bits>,affinity=<list_of_vcpus_with_their_associated_cpuset>,features=<list_of_features_to_enable>
|
||||
/// boot=<boot_vcpus>, max=<max_vcpus>, topology=<threads_per_core>:<cores_per_die>:<dies_per_package>:<packages>, kvm_hyperv=on|off, max_phys_bits=<maximum_number_of_physical_bits>, affinity=<list_of_vcpus_with_their_associated_cpuset>, features=<list_of_features_to_enable>
|
||||
cpus: String,
|
||||
|
||||
#[argh(option, long = "platform")]
|
||||
/// num_pci_segments=<num_pci_segments>,iommu_segments=<list_of_segments>,serial_number=<dmi_device_serial_number>,uuid=<dmi_device_uuid>,oem_strings=<list_of_strings>
|
||||
/// num_pci_segments=<num_pci_segments>, iommu_segments=<list_of_segments>, serial_number=<dmi_device_serial_number>, uuid=<dmi_device_uuid>, oem_strings=<list_of_strings>
|
||||
platform: Option<String>,
|
||||
|
||||
#[argh(option, long = "memory", default = "default_memory()")]
|
||||
/// size=<guest_memory_size>,mergeable=on|off,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,hotplug_method=acpi|virtio-mem,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off,thp=on|off
|
||||
/// size=<guest_memory_size>, mergeable=on|off, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, hotplug_method=acpi|virtio-mem, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off, thp=on|off
|
||||
memory: String,
|
||||
|
||||
#[argh(option, long = "memory-zone")]
|
||||
/// size=<guest_memory_region_size>,file=<backing_file>,shared=on|off,hugepages=on|off,hugepage_size=<hugepage_size>,host_numa_node=<node_id>,id=<zone_identifier>,hotplug_size=<hotpluggable_memory_size>,hotplugged_size=<hotplugged_memory_size>,prefault=on|off
|
||||
/// size=<guest_memory_region_size>, file=<backing_file>, shared=on|off, hugepages=on|off, hugepage_size=<hugepage_size>, host_numa_node=<node_id>, id=<zone_identifier>, hotplug_size=<hotpluggable_memory_size>, hotplugged_size=<hotplugged_memory_size>, prefault=on|off
|
||||
memory_zone: Vec<String>,
|
||||
|
||||
#[argh(option, long = "firmware")]
|
||||
@@ -168,27 +178,27 @@ pub struct TopLevel {
|
||||
cmdline: Option<String>,
|
||||
|
||||
#[argh(option, long = "disk")]
|
||||
/// path=<disk_image_path>,readonly=on|off,direct=on|off,iommu=on|off,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,vhost_user=on|off,socket=<vhost_user_socket_path>,bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,id=<device_id>,pci_segment=<segment_id>
|
||||
/// path=<disk_image_path>, readonly=on|off, direct=on|off, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, vhost_user=on|off, socket=<vhost_user_socket_path>, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, id=<device_id>, pci_segment=<segment_id>
|
||||
disk: Vec<String>,
|
||||
|
||||
#[argh(option, long = "net")]
|
||||
/// tap=<if_name>,ip=<ip_addr>,mask=<net_mask>,mac=<mac_addr>,fd=<fd1,fd2...>,iommu=on|off,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,vhost_user=<vhost_user_enable>,socket=<vhost_user_socket_path>,vhost_mode=client|server,bw_size=<bytes>,bw_one_time_burst=<bytes>,bw_refill_time=<ms>,ops_size=<io_ops>,ops_one_time_burst=<io_ops>,ops_refill_time=<ms>,pci_segment=<segment_id>offload_tso=on|off,offload_ufo=on|off,offload_csum=on|off
|
||||
/// tap=<if_name>, ip=<ip_addr>, mask=<net_mask>, mac=<mac_addr>, fd=<fd1,fd2...>, iommu=on|off, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, vhost_user=<vhost_user_enable>, socket=<vhost_user_socket_path>, vhost_mode=client|server, bw_size=<bytes>, bw_one_time_burst=<bytes>, bw_refill_time=<ms>, ops_size=<io_ops>, ops_one_time_burst=<io_ops>, ops_refill_time=<ms>, pci_segment=<segment_id>offload_tso=on|off, offload_ufo=on|off, offload_csum=on|off
|
||||
net: Vec<String>,
|
||||
|
||||
#[argh(option, long = "rng", default = "default_rng()")]
|
||||
/// src=<entropy_source_path>,iommu=on|off
|
||||
/// src=<entropy_source_path>, iommu=on|off
|
||||
rng: String,
|
||||
|
||||
#[argh(option, long = "balloon")]
|
||||
/// size=<balloon_size>,deflate_on_oom=on|off,free_page_reporting=on|off
|
||||
/// size=<balloon_size>, deflate_on_oom=on|off, free_page_reporting=on|off
|
||||
balloon: Option<String>,
|
||||
|
||||
#[argh(option, long = "fs")]
|
||||
/// tag=<tag_name>,socket=<socket_path>,num_queues=<number_of_queues>,queue_size=<size_of_each_queue>,id=<device_id>,pci_segment=<segment_id>
|
||||
/// tag=<tag_name>, socket=<socket_path>, num_queues=<number_of_queues>, queue_size=<size_of_each_queue>, id=<device_id>, pci_segment=<segment_id>
|
||||
fs: Vec<String>,
|
||||
|
||||
#[argh(option, long = "pmem")]
|
||||
/// file=<backing_file_path>,size=<persistent_memory_size>,iommu=on|off,discard_writes=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
/// file=<backing_file_path>, size=<persistent_memory_size>, iommu=on|off, discard_writes=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
pmem: Vec<String>,
|
||||
|
||||
#[argh(option, long = "serial", default = "String::from(\"null\")")]
|
||||
@@ -196,27 +206,27 @@ pub struct TopLevel {
|
||||
serial: String,
|
||||
|
||||
#[argh(option, long = "console", default = "String::from(\"tty\")")]
|
||||
/// off|null|pty|tty|file=/path/to/a/file,iommu=on|off
|
||||
/// off|null|pty|tty|file=/path/to/a/file, iommu=on|off
|
||||
console: String,
|
||||
|
||||
#[argh(option, long = "device")]
|
||||
/// path=<device_path>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
/// path=<device_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "user-device")]
|
||||
/// socket=<socket_path>,id=<device_id>,pci_segment=<segment_id>
|
||||
/// socket=<socket_path>, id=<device_id>, pci_segment=<segment_id>
|
||||
user_device: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vdpa")]
|
||||
/// path=<device_path>,num_queues=<number_of_queues>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
/// path=<device_path>, num_queues=<number_of_queues>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
vdpa: Vec<String>,
|
||||
|
||||
#[argh(option, long = "vsock")]
|
||||
/// cid=<context_id>,socket=<socket_path>,iommu=on|off,id=<device_id>,pci_segment=<segment_id>
|
||||
/// cid=<context_id>, socket=<socket_path>, iommu=on|off, id=<device_id>, pci_segment=<segment_id>
|
||||
vsock: Option<String>,
|
||||
|
||||
#[argh(option, long = "numa")]
|
||||
/// guest_numa_id=<node_id>,cpus=<cpus_id>,distances=<list_of_distances_to_destination_nodes>,memory_zones=<list_of_memory_zones>,sgx_epc_sections=<list_of_sgx_epc_sections>
|
||||
/// guest_numa_id=<node_id>, cpus=<cpus_id>, distances=<list_of_distances_to_destination_nodes>, memory_zones=<list_of_memory_zones>, sgx_epc_sections=<list_of_sgx_epc_sections>
|
||||
numa: Vec<String>,
|
||||
|
||||
#[argh(switch, long = "watchdog")]
|
||||
@@ -235,12 +245,27 @@ pub struct TopLevel {
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
api_socket: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-service-name")]
|
||||
/// well known name of the service
|
||||
dbus_name: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(option, long = "dbus-object-path")]
|
||||
/// object path to serve the dbus interface
|
||||
dbus_path: Option<String>,
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
#[argh(switch, long = "dbus-system-bus")]
|
||||
/// use the system bus instead of a session bus
|
||||
dbus_system_bus: bool,
|
||||
|
||||
#[argh(option, long = "event-monitor")]
|
||||
/// path=<path/to/a/file>|fd=<fd>
|
||||
event_monitor: Option<String>,
|
||||
|
||||
#[argh(option, long = "restore")]
|
||||
/// source_url=<source_url>,prefault=on|off
|
||||
/// source_url=<source_url>, prefault=on|off
|
||||
restore: Option<String>,
|
||||
|
||||
#[argh(option, long = "seccomp", default = "String::from(\"true\")")]
|
||||
@@ -253,7 +278,7 @@ pub struct TopLevel {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[argh(option, long = "sgx-epc")]
|
||||
/// id=<epc_section_identifier>,size=<epc_section_size>,prefault=on|off
|
||||
/// id=<epc_section_identifier>, size=<epc_section_size>, prefault=on|off
|
||||
sgx_epc: Vec<String>,
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
@@ -414,6 +439,18 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
#[cfg(feature = "dbus_api")]
|
||||
let dbus_options = match (&toplevel.dbus_name, &toplevel.dbus_path) {
|
||||
(Some(ref name), Some(ref path)) => Ok(Some(DBusApiOptions {
|
||||
service_name: name.to_owned(),
|
||||
object_path: path.to_owned(),
|
||||
system_bus: toplevel.dbus_system_bus,
|
||||
})),
|
||||
(Some(_), None) => Err(Error::MissingDBusObjectPath),
|
||||
(None, Some(_)) => Err(Error::MissingDBusServiceName),
|
||||
(None, None) => Ok(None),
|
||||
}?;
|
||||
|
||||
if let Some(ref monitor_config) = toplevel.event_monitor {
|
||||
let mut parser = OptionParser::new();
|
||||
parser.add("path").add("fd");
|
||||
@@ -443,7 +480,7 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
let (api_request_sender, api_request_receiver) = channel();
|
||||
let api_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateApiEventFd)?;
|
||||
|
||||
let http_sender = api_request_sender.clone();
|
||||
let api_request_sender_clone = api_request_sender.clone();
|
||||
let seccomp_action = match &toplevel.seccomp as &str {
|
||||
"true" => SeccompAction::Trap,
|
||||
"false" => SeccompAction::Allow,
|
||||
@@ -509,12 +546,16 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
||||
|
||||
let vmm_thread = vmm::start_vmm_thread(
|
||||
env!("CARGO_PKG_VERSION").to_string(),
|
||||
let exit_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateExitEventFd)?;
|
||||
|
||||
let vmm_thread_handle = vmm::start_vmm_thread(
|
||||
vmm::VmmVersionInfo::new(env!("BUILD_VERSION"), env!("CARGO_PKG_VERSION")),
|
||||
&api_socket_path,
|
||||
api_socket_fd,
|
||||
#[cfg(feature = "dbus_api")]
|
||||
dbus_options,
|
||||
api_evt.try_clone().unwrap(),
|
||||
http_sender,
|
||||
api_request_sender_clone,
|
||||
api_request_receiver,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
gdb_socket_path,
|
||||
@@ -522,41 +563,60 @@ fn start_vmm(toplevel: TopLevel) -> Result<Option<String>, Error> {
|
||||
debug_evt.try_clone().unwrap(),
|
||||
#[cfg(feature = "guest_debug")]
|
||||
vm_debug_evt.try_clone().unwrap(),
|
||||
exit_evt.try_clone().unwrap(),
|
||||
&seccomp_action,
|
||||
hypervisor,
|
||||
)
|
||||
.map_err(Error::StartVmmThread)?;
|
||||
|
||||
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
|
||||
let r: Result<(), Error> = (|| {
|
||||
let payload_present = toplevel.kernel.is_some() || toplevel.firmware.is_some();
|
||||
|
||||
if payload_present {
|
||||
let vm_params = toplevel.to_vm_params();
|
||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||
if payload_present {
|
||||
let vm_params = toplevel.to_vm_params();
|
||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||
|
||||
// Create and boot the VM based off the VM config we just built.
|
||||
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)?;
|
||||
} else if let Some(restore_params) = toplevel.restore {
|
||||
vmm::api::vm_restore(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?),
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
// 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)?;
|
||||
} else if let Some(restore_params) = toplevel.restore {
|
||||
vmm::api::vm_restore(
|
||||
api_evt.try_clone().unwrap(),
|
||||
api_request_sender,
|
||||
Arc::new(
|
||||
config::RestoreConfig::parse(&restore_params).map_err(Error::ParsingRestore)?,
|
||||
),
|
||||
)
|
||||
.map_err(Error::VmRestore)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})();
|
||||
|
||||
if r.is_err() {
|
||||
if let Err(e) = exit_evt.write(1) {
|
||||
warn!("writing to exit EventFd: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
vmm_thread
|
||||
vmm_thread_handle
|
||||
.thread_handle
|
||||
.join()
|
||||
.map_err(Error::ThreadJoin)?
|
||||
.map_err(Error::VmmThread)?;
|
||||
|
||||
Ok(api_socket_path)
|
||||
#[cfg(feature = "dbus_api")]
|
||||
if let Some(chs) = vmm_thread_handle.dbus_shutdown_chs {
|
||||
dbus_api_graceful_shutdown(chs);
|
||||
}
|
||||
|
||||
r.map(|_| api_socket_path)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@@ -570,7 +630,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
2
test_data/cloud-init/ubuntu/local/meta-data
Normal file
2
test_data/cloud-init/ubuntu/local/meta-data
Normal file
@@ -0,0 +1,2 @@
|
||||
instance-id: cloud
|
||||
local-hostname: cloud
|
||||
7
test_data/cloud-init/ubuntu/local/network-config
Normal file
7
test_data/cloud-init/ubuntu/local/network-config
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
ethernets:
|
||||
ens4:
|
||||
match:
|
||||
macaddress: 12:34:56:78:90:ab
|
||||
addresses: [192.168.249.2/24]
|
||||
gateway4: 192.168.249.1
|
||||
10
test_data/cloud-init/ubuntu/local/user-data
Normal file
10
test_data/cloud-init/ubuntu/local/user-data
Normal file
@@ -0,0 +1,10 @@
|
||||
#cloud-config
|
||||
users:
|
||||
- name: cloud
|
||||
passwd: $6$7125787751a8d18a$sHwGySomUA1PawiNFWVCKYQN.Ec.Wzz0JtPPL1MvzFrkwmop2dq7.4CYf03A5oemPQ4pOFCCrtCelvFBEle/K.
|
||||
sudo: ALL=(ALL) NOPASSWD:ALL
|
||||
lock_passwd: False
|
||||
inactive: False
|
||||
shell: /bin/bash
|
||||
|
||||
ssh_pwauth: True
|
||||
@@ -5,12 +5,12 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
dirs = "4.0.0"
|
||||
dirs = "5.0.0"
|
||||
epoll = "4.3.1"
|
||||
libc = "0.2.139"
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.93"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
ssh2 = { version = "0.9.4", features = ["vendored-openssl"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
wait-timeout = "0.2.0"
|
||||
|
||||
@@ -249,7 +249,8 @@ impl DiskConfig for UbuntuDiskConfig {
|
||||
.unwrap()
|
||||
.join("test_data")
|
||||
.join("cloud-init")
|
||||
.join("ubuntu");
|
||||
.join("ubuntu")
|
||||
.join("ci");
|
||||
|
||||
vec!["meta-data"].iter().for_each(|x| {
|
||||
rate_limited_copy(source_file_dir.join(x), cloud_init_directory.join(x))
|
||||
@@ -868,14 +869,6 @@ impl Guest {
|
||||
.map_err(Error::Parsing)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub fn get_initial_apicid(&self) -> Result<u32, Error> {
|
||||
self.ssh_command("grep \"initial apicid\" /proc/cpuinfo | grep -o \"[0-9]*\"")?
|
||||
.trim()
|
||||
.parse()
|
||||
.map_err(Error::Parsing)
|
||||
}
|
||||
|
||||
pub fn get_total_memory(&self) -> Result<u32, Error> {
|
||||
self.ssh_command("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")?
|
||||
.trim()
|
||||
@@ -1352,6 +1345,7 @@ pub fn parse_iperf3_output(output: &[u8], sender: bool, bandwidth: bool) -> Resu
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FioOps {
|
||||
Read,
|
||||
RandomRead,
|
||||
|
||||
@@ -30,6 +30,9 @@ use test_infra::*;
|
||||
use vmm_sys_util::{tempdir::TempDir, tempfile::TempFile};
|
||||
use wait_timeout::ChildExt;
|
||||
|
||||
// Constant taken from the VMM crate.
|
||||
const MAX_NUM_PCI_SEGMENTS: u16 = 96;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
mod x86_64 {
|
||||
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
|
||||
@@ -70,6 +73,324 @@ const DIRECT_KERNEL_BOOT_CMDLINE: &str =
|
||||
|
||||
const CONSOLE_TEST_STRING: &str = "Started OpenBSD Secure Shell server";
|
||||
|
||||
// This enum exists to make it more convenient to
|
||||
// implement test for both D-Bus and REST APIs.
|
||||
enum TargetApi {
|
||||
// API socket
|
||||
HttpApi(String),
|
||||
// well known service name, object path
|
||||
DBusApi(String, String),
|
||||
}
|
||||
|
||||
impl TargetApi {
|
||||
fn new_http_api(tmp_dir: &TempDir) -> Self {
|
||||
Self::HttpApi(temp_api_path(tmp_dir))
|
||||
}
|
||||
|
||||
fn new_dbus_api(tmp_dir: &TempDir) -> Self {
|
||||
// `tmp_dir` is in the form of "/tmp/chXXXXXX"
|
||||
// and we take the `chXXXXXX` part as a unique identifier for the guest
|
||||
let id = tmp_dir.as_path().file_name().unwrap().to_str().unwrap();
|
||||
|
||||
Self::DBusApi(
|
||||
format!("org.cloudhypervisor.{id}"),
|
||||
format!("/org/cloudhypervisor/{id}"),
|
||||
)
|
||||
}
|
||||
|
||||
fn guest_args(&self) -> Vec<&str> {
|
||||
match self {
|
||||
TargetApi::HttpApi(api_socket) => {
|
||||
vec!["--api-socket", api_socket.as_str()]
|
||||
}
|
||||
TargetApi::DBusApi(service_name, object_path) => {
|
||||
vec![
|
||||
"--dbus-service-name",
|
||||
service_name.as_str(),
|
||||
"--dbus-object-path",
|
||||
object_path.as_str(),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remote_args(&self) -> Vec<&str> {
|
||||
// `guest_args` and `remote_args` are consistent with each other
|
||||
self.guest_args()
|
||||
}
|
||||
|
||||
fn remote_command(&self, command: &str, arg: Option<&str>) -> bool {
|
||||
let mut cmd = Command::new(clh_command("ch-remote"));
|
||||
cmd.args(self.remote_args());
|
||||
cmd.arg(command);
|
||||
|
||||
if let Some(arg) = arg {
|
||||
cmd.arg(arg);
|
||||
}
|
||||
|
||||
let output = cmd.output().unwrap();
|
||||
if output.status.success() {
|
||||
true
|
||||
} else {
|
||||
eprintln!("Error running ch-remote command: {:?}", &cmd);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
eprintln!("stderr: {stderr}");
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
fn _test_api_create_boot(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config),));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be shutdown and then
|
||||
// booted again
|
||||
fn _test_api_shutdown(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shut it down
|
||||
assert!(target_api.remote_command("shutdown", None));
|
||||
|
||||
// Then boot it again
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be deleted and then recreated
|
||||
// booted again.
|
||||
fn _test_api_delete(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then delete it
|
||||
assert!(target_api.remote_command("delete", None));
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it again
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
// Then we pause the VM, check that it's no longer available.
|
||||
// Finally we resume the VM and check that it's available.
|
||||
fn _test_api_pause_resume(target_api: TargetApi, guest: Guest) {
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(target_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
assert!(target_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
assert!(target_api.remote_command("create", Some(create_config)));
|
||||
|
||||
// Then boot it
|
||||
assert!(target_api.remote_command("boot", None));
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// We now pause the VM
|
||||
assert!(target_api.remote_command("pause", None));
|
||||
|
||||
// Check pausing again fails
|
||||
assert!(!target_api.remote_command("pause", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// SSH into the VM should fail
|
||||
assert!(ssh_command_ip(
|
||||
"grep -c processor /proc/cpuinfo",
|
||||
&guest.network.guest_ip,
|
||||
2,
|
||||
5
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// Resume the VM
|
||||
assert!(target_api.remote_command("resume", None));
|
||||
|
||||
// Check resuming again fails
|
||||
assert!(!target_api.remote_command("resume", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// Now we should be able to SSH back in and get the right number of CPUs
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
fn prepare_virtiofsd(tmp_dir: &TempDir, shared_dir: &str) -> (std::process::Child, String) {
|
||||
let mut workload_path = dirs::home_dir().unwrap();
|
||||
workload_path.push("workloads");
|
||||
@@ -252,26 +573,6 @@ fn prepare_swtpm_daemon(tmp_dir: &TempDir) -> (std::process::Command, String) {
|
||||
(swtpm_command, swtpm_socket_path)
|
||||
}
|
||||
|
||||
fn curl_command(api_socket: &str, method: &str, url: &str, http_body: Option<&str>) {
|
||||
let mut curl_args: Vec<&str> = ["--unix-socket", api_socket, "-i", "-X", method, url].to_vec();
|
||||
|
||||
if let Some(body) = http_body {
|
||||
curl_args.push("-H");
|
||||
curl_args.push("Accept: application/json");
|
||||
curl_args.push("-H");
|
||||
curl_args.push("Content-Type: application/json");
|
||||
curl_args.push("-d");
|
||||
curl_args.push(body);
|
||||
}
|
||||
|
||||
let status = Command::new("curl")
|
||||
.args(curl_args)
|
||||
.status()
|
||||
.expect("Failed to launch curl command");
|
||||
|
||||
assert!(status.success());
|
||||
}
|
||||
|
||||
fn remote_command(api_socket: &str, command: &str, arg: Option<&str>) -> bool {
|
||||
let mut cmd = Command::new(clh_command("ch-remote"));
|
||||
cmd.args(["--api-socket", api_socket, command]);
|
||||
@@ -1224,7 +1525,10 @@ fn _test_virtio_fs(
|
||||
.default_net()
|
||||
.args(["--api-socket", &api_socket]);
|
||||
if pci_segment.is_some() {
|
||||
guest_command.args(["--platform", "num_pci_segments=16"]);
|
||||
guest_command.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
}
|
||||
|
||||
let fs_params = format!(
|
||||
@@ -1960,7 +2264,6 @@ mod common_parallel {
|
||||
guest.wait_vm_boot(Some(120)).unwrap();
|
||||
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default(), 1);
|
||||
assert_eq!(guest.get_initial_apicid().unwrap_or(1), 0);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
assert_eq!(guest.get_pci_bridge_class().unwrap_or_default(), "0x060000");
|
||||
|
||||
@@ -2064,19 +2367,16 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_cpu_topology_421() {
|
||||
test_cpu_topology(4, 2, 1, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_cpu_topology_142() {
|
||||
test_cpu_topology(1, 4, 2, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_cpu_topology_262() {
|
||||
test_cpu_topology(2, 6, 2, false);
|
||||
}
|
||||
@@ -2248,7 +2548,7 @@ mod common_parallel {
|
||||
"--memory-zone",
|
||||
"id=mem0,size=1G,hotplug_size=2G",
|
||||
"--memory-zone",
|
||||
"id=mem1,size=1G,file=/dev/shm",
|
||||
"id=mem1,size=1G,shared=on",
|
||||
"--memory-zone",
|
||||
"id=mem2,size=1G,host_numa_node=0,hotplug_size=2G",
|
||||
])
|
||||
@@ -2337,7 +2637,10 @@ mod common_parallel {
|
||||
.args(["--memory", "size=512M"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
.args(["--platform", "num_pci_segments=16,iommu_segments=[1]"])
|
||||
.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS},iommu_segments=[1]"),
|
||||
])
|
||||
.default_disks()
|
||||
.capture_output()
|
||||
.default_net();
|
||||
@@ -2493,7 +2796,10 @@ mod common_parallel {
|
||||
.args(["--memory", "size=512M"])
|
||||
.args(["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||
.args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||
.args(["--platform", "num_pci_segments=16"])
|
||||
.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
])
|
||||
.args([
|
||||
"--disk",
|
||||
format!(
|
||||
@@ -2520,15 +2826,15 @@ mod common_parallel {
|
||||
let grep_cmd = "lspci | grep \"Host bridge\" | wc -l";
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// There should be 16 PCI host bridges in the guest.
|
||||
// There should be MAX_NUM_PCI_SEGMENTS PCI host bridges in the guest.
|
||||
assert_eq!(
|
||||
guest
|
||||
.ssh_command(grep_cmd)
|
||||
.unwrap()
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.parse::<u16>()
|
||||
.unwrap_or_default(),
|
||||
16
|
||||
MAX_NUM_PCI_SEGMENTS
|
||||
);
|
||||
|
||||
// Check both if /dev/vdc exists and if the block size is 4M.
|
||||
@@ -3744,7 +4050,7 @@ mod common_parallel {
|
||||
// line (We tag the command line from cloud-hypervisor for that purpose).
|
||||
// The third device is added to validate that hotplug works correctly since
|
||||
// it is being added to the L2 VM through hotplugging mechanism.
|
||||
// Also, we pass-through a vitio-blk device to the L2 VM to test the 32-bit
|
||||
// Also, we pass-through a virtio-blk device to the L2 VM to test the 32-bit
|
||||
// vfio device support
|
||||
fn test_vfio() {
|
||||
setup_vfio_network_interfaces();
|
||||
@@ -3989,7 +4295,7 @@ mod common_parallel {
|
||||
.ssh_command_l1(
|
||||
"sudo /mnt/ch-remote \
|
||||
--api-socket /tmp/ch_api.sock \
|
||||
resize --memory=1073741824",
|
||||
resize --memory 1073741824",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);
|
||||
@@ -4048,299 +4354,35 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
fn test_api_create_boot() {
|
||||
fn test_api_http_shutdown() {
|
||||
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 mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, http_body).unwrap();
|
||||
|
||||
remote_command(
|
||||
&api_socket,
|
||||
"create",
|
||||
Some(temp_config_path.as_os_str().to_str().unwrap()),
|
||||
);
|
||||
|
||||
// Then boot it
|
||||
remote_command(&api_socket, "boot", None);
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
_test_api_shutdown(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be shutdown and then
|
||||
// booted again
|
||||
fn test_api_shutdown() {
|
||||
fn test_api_http_delete() {
|
||||
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 mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.create",
|
||||
Some(&http_body),
|
||||
);
|
||||
|
||||
// Then boot it
|
||||
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shut it down
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.shutdown",
|
||||
None,
|
||||
);
|
||||
|
||||
// Then boot it again
|
||||
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
_test_api_delete(TargetApi::new_http_api(&guest.tmp_dir), guest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check it can be deleted and then recreated
|
||||
// booted again.
|
||||
fn test_api_delete() {
|
||||
fn test_api_http_pause_resume() {
|
||||
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 mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.create",
|
||||
Some(&http_body),
|
||||
);
|
||||
|
||||
// Then boot it
|
||||
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then delete it
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.delete",
|
||||
None,
|
||||
);
|
||||
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.create",
|
||||
Some(&http_body),
|
||||
);
|
||||
|
||||
// Then boot it again
|
||||
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
|
||||
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
_test_api_pause_resume(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Start cloud-hypervisor with no VM parameters, only the API server running.
|
||||
// From the API: Create a VM, boot it and check that it looks as expected.
|
||||
// Then we pause the VM, check that it's no longer available.
|
||||
// Finally we resume the VM and check that it's available.
|
||||
fn test_api_pause_resume() {
|
||||
fn test_api_http_create_boot() {
|
||||
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 mut child = GuestCommand::new(&guest)
|
||||
.args(["--api-socket", &api_socket])
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API server is running
|
||||
curl_command(&api_socket, "GET", "http://localhost/api/v1/vmm.ping", None);
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let http_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
curl_command(
|
||||
&api_socket,
|
||||
"PUT",
|
||||
"http://localhost/api/v1/vm.create",
|
||||
Some(&http_body),
|
||||
);
|
||||
|
||||
// Then boot it
|
||||
curl_command(&api_socket, "PUT", "http://localhost/api/v1/vm.boot", None);
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// We now pause the VM
|
||||
assert!(remote_command(&api_socket, "pause", None));
|
||||
|
||||
// Check pausing again fails
|
||||
assert!(!remote_command(&api_socket, "pause", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// SSH into the VM should fail
|
||||
assert!(ssh_command_ip(
|
||||
"grep -c processor /proc/cpuinfo",
|
||||
&guest.network.guest_ip,
|
||||
2,
|
||||
5
|
||||
)
|
||||
.is_err());
|
||||
|
||||
// Resume the VM
|
||||
assert!(remote_command(&api_socket, "resume", None));
|
||||
|
||||
// Check resuming again fails
|
||||
assert!(!remote_command(&api_socket, "resume", None));
|
||||
|
||||
thread::sleep(std::time::Duration::new(2, 0));
|
||||
|
||||
// Now we should be able to SSH back in and get the right number of CPUs
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
_test_api_create_boot(TargetApi::new_http_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -4954,7 +4996,6 @@ mod common_parallel {
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn create_loop_device(backing_file_path: &str, block_size: u32, num_retries: usize) -> String {
|
||||
const LOOP_CONFIGURE: u64 = 0x4c0a;
|
||||
const LOOP_CTL_GET_FREE: u64 = 0x4c82;
|
||||
@@ -5015,12 +5056,9 @@ mod common_parallel {
|
||||
.unwrap();
|
||||
|
||||
// Request a free loop device
|
||||
let loop_device_number = unsafe {
|
||||
libc::ioctl(
|
||||
loop_ctl_file.as_raw_fd(),
|
||||
LOOP_CTL_GET_FREE.try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
let loop_device_number =
|
||||
unsafe { libc::ioctl(loop_ctl_file.as_raw_fd(), LOOP_CTL_GET_FREE as _) };
|
||||
|
||||
if loop_device_number < 0 {
|
||||
panic!("Couldn't find a free loop device");
|
||||
}
|
||||
@@ -5052,7 +5090,7 @@ mod common_parallel {
|
||||
let ret = unsafe {
|
||||
libc::ioctl(
|
||||
loop_device_file.as_raw_fd(),
|
||||
LOOP_CONFIGURE.try_into().unwrap(),
|
||||
LOOP_CONFIGURE as _,
|
||||
&loop_config,
|
||||
)
|
||||
};
|
||||
@@ -5237,6 +5275,7 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_virtio_balloon_free_page_reporting() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
@@ -5336,7 +5375,10 @@ mod common_parallel {
|
||||
.capture_output();
|
||||
|
||||
if pci_segment.is_some() {
|
||||
cmd.args(["--platform", "num_pci_segments=16"]);
|
||||
cmd.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
}
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
@@ -5472,7 +5514,10 @@ mod common_parallel {
|
||||
.capture_output();
|
||||
|
||||
if pci_segment.is_some() {
|
||||
cmd.args(["--platform", "num_pci_segments=16"]);
|
||||
cmd.args([
|
||||
"--platform",
|
||||
&format!("num_pci_segments={MAX_NUM_PCI_SEGMENTS}"),
|
||||
]);
|
||||
}
|
||||
|
||||
let mut child = cmd.spawn().unwrap();
|
||||
@@ -6300,11 +6345,13 @@ mod common_parallel {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
|
||||
fn test_macvtap() {
|
||||
_test_macvtap(false, "guestmacvtap0", "hostmacvtap0")
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_arch = "aarch64", ignore = "See #5443")]
|
||||
fn test_macvtap_hotplug() {
|
||||
_test_macvtap(true, "guestmacvtap1", "hostmacvtap1")
|
||||
}
|
||||
@@ -6814,6 +6861,116 @@ mod common_parallel {
|
||||
}
|
||||
}
|
||||
|
||||
mod dbus_api {
|
||||
use crate::*;
|
||||
|
||||
// Start cloud-hypervisor with no VM parameters, running both the HTTP
|
||||
// and DBus APIs. Alternate calls to the external APIs (HTTP and DBus)
|
||||
// to create a VM, boot it, and verify that it can be shut down and then
|
||||
// booted again.
|
||||
#[test]
|
||||
fn test_api_dbus_and_http_interleaved() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
let dbus_api = TargetApi::new_dbus_api(&guest.tmp_dir);
|
||||
let http_api = TargetApi::new_http_api(&guest.tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(&guest)
|
||||
.args(dbus_api.guest_args())
|
||||
.args(http_api.guest_args())
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(1, 0));
|
||||
|
||||
// Verify API servers are running
|
||||
assert!(dbus_api.remote_command("ping", None));
|
||||
assert!(http_api.remote_command("ping", None));
|
||||
|
||||
// Create the VM first
|
||||
let cpu_count: u8 = 4;
|
||||
let request_body = guest.api_create_body(
|
||||
cpu_count,
|
||||
direct_kernel_boot_path().to_str().unwrap(),
|
||||
DIRECT_KERNEL_BOOT_CMDLINE,
|
||||
);
|
||||
|
||||
let temp_config_path = guest.tmp_dir.as_path().join("config");
|
||||
std::fs::write(&temp_config_path, request_body).unwrap();
|
||||
let create_config = temp_config_path.as_os_str().to_str().unwrap();
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Create the VM
|
||||
assert!(dbus_api.remote_command("create", Some(create_config),));
|
||||
|
||||
// Then boot it
|
||||
assert!(http_api.remote_command("boot", None));
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
|
||||
// Sync and shutdown without powering off to prevent filesystem
|
||||
// corruption.
|
||||
guest.ssh_command("sync").unwrap();
|
||||
guest.ssh_command("sudo shutdown -H now").unwrap();
|
||||
|
||||
// Wait for the guest to be fully shutdown
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Then shutdown the VM
|
||||
assert!(dbus_api.remote_command("shutdown", None));
|
||||
|
||||
// Then boot it again
|
||||
assert!(http_api.remote_command("boot", None));
|
||||
guest.wait_vm_boot(None).unwrap();
|
||||
|
||||
// Check that the VM booted as expected
|
||||
assert_eq!(guest.get_cpu_count().unwrap_or_default() as u8, cpu_count);
|
||||
assert!(guest.get_total_memory().unwrap_or_default() > 480_000);
|
||||
});
|
||||
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_create_boot() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_create_boot(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_shutdown() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_shutdown(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_delete() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_delete(TargetApi::new_dbus_api(&guest.tmp_dir), guest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_api_dbus_pause_resume() {
|
||||
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||
let guest = Guest::new(Box::new(focal));
|
||||
|
||||
_test_api_pause_resume(TargetApi::new_dbus_api(&guest.tmp_dir), guest)
|
||||
}
|
||||
}
|
||||
|
||||
mod common_sequential {
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
use crate::*;
|
||||
@@ -8125,7 +8282,7 @@ mod vfio {
|
||||
.ssh_command_l1(
|
||||
"sudo /mnt/ch-remote \
|
||||
--api-socket /tmp/ch_api.sock \
|
||||
resize --memory=1073741824",
|
||||
resize --memory 1073741824",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(guest.get_total_memory_l2().unwrap_or_default() > 960_000);
|
||||
|
||||
@@ -309,11 +309,7 @@ impl Emulator {
|
||||
}
|
||||
|
||||
self.established_flag_cached = true;
|
||||
if est.resp.bit != 0 {
|
||||
self.established_flag = false;
|
||||
} else {
|
||||
self.established_flag = true;
|
||||
}
|
||||
self.established_flag = est.resp.bit == 0;
|
||||
|
||||
self.established_flag
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@ edition = "2021"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
once_cell = "1.17.1"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.93"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
|
||||
[features]
|
||||
tracing = []
|
||||
|
||||
@@ -11,5 +11,5 @@ crc32c = "0.6.3"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
remain = "0.2.6"
|
||||
thiserror = "1.0.38"
|
||||
uuid = { version = "1.3.0", features = ["v4"] }
|
||||
thiserror = "1.0.40"
|
||||
uuid = { version = "1.3.4", features = ["v4"] }
|
||||
|
||||
@@ -145,11 +145,7 @@ impl DiskSpec {
|
||||
let bits = f
|
||||
.read_u32::<LittleEndian>()
|
||||
.map_err(VhdxMetadataError::ReadMetadata)?;
|
||||
if bits & BLOCK_HAS_PARENT != 0 {
|
||||
disk_spec.has_parent = true;
|
||||
} else {
|
||||
disk_spec.has_parent = false;
|
||||
}
|
||||
disk_spec.has_parent = bits & BLOCK_HAS_PARENT != 0;
|
||||
|
||||
metadata_presence |= METADATA_FILE_PARAMETER_PRESENT;
|
||||
} else if metadata_entry.item_id
|
||||
|
||||
@@ -14,10 +14,10 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
option_parser = { path = "../option_parser" }
|
||||
qcow = { path = "../qcow" }
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.8.0"
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.9.0"
|
||||
virtio-bindings = "0.2.0"
|
||||
virtio-queue = "0.7.0"
|
||||
vm-memory = "0.10.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-memory = "0.11.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@ libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_util = { path = "../net_util" }
|
||||
option_parser = { path = "../option_parser" }
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.8.0"
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-slave"] }
|
||||
vhost-user-backend = "0.9.0"
|
||||
virtio-bindings = "0.2.0"
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ fn main() {
|
||||
let toplevel: TopLevel = argh::from_env();
|
||||
|
||||
if toplevel.version {
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILT_VERSION"));
|
||||
println!("{} {}", env!("CARGO_BIN_NAME"), env!("BUILD_VERSION"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ edition = "2021"
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
arc-swap = "1.5.1"
|
||||
block_util = { path = "../block_util" }
|
||||
byteorder = "1.4.3"
|
||||
epoll = "4.3.1"
|
||||
event_monitor = { path = "../event_monitor" }
|
||||
io-uring = "0.5.12"
|
||||
io-uring = "0.5.13"
|
||||
libc = "0.2.139"
|
||||
log = "0.4.17"
|
||||
net_gen = { path = "../net_gen" }
|
||||
@@ -22,18 +22,18 @@ net_util = { path = "../net_util" }
|
||||
pci = { path = "../pci" }
|
||||
rate_limiter = { path = "../rate_limiter" }
|
||||
seccompiler = "0.3.0"
|
||||
serde = { version = "1.0.151", features = ["derive"] }
|
||||
serde_json = "1.0.93"
|
||||
serde = { version = "1.0.164", features = ["derive"] }
|
||||
serde_json = "1.0.96"
|
||||
serial_buffer = { path = "../serial_buffer" }
|
||||
thiserror = "1.0.38"
|
||||
versionize = "0.1.9"
|
||||
thiserror = "1.0.40"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vhost = { version = "0.6.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
|
||||
vhost = { version = "0.7.0", features = ["vhost-user-master", "vhost-user-slave", "vhost-kern", "vhost-vdpa"] }
|
||||
virtio-bindings = { version = "0.2.0", features = ["virtio-v5_0_0"] }
|
||||
virtio-queue = "0.7.0"
|
||||
virtio-queue = "0.8.0"
|
||||
vm-allocator = { path = "../vm-allocator" }
|
||||
vm-device = { path = "../vm-device" }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
vm-virtio = { path = "../vm-virtio" }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
@@ -39,19 +39,24 @@ pub mod vhost_user;
|
||||
pub mod vsock;
|
||||
pub mod watchdog;
|
||||
|
||||
pub use self::balloon::*;
|
||||
pub use self::block::*;
|
||||
pub use self::console::*;
|
||||
pub use self::device::*;
|
||||
pub use self::epoll_helper::*;
|
||||
pub use self::iommu::*;
|
||||
pub use self::mem::*;
|
||||
pub use self::net::*;
|
||||
pub use self::pmem::*;
|
||||
pub use self::rng::*;
|
||||
pub use self::vdpa::*;
|
||||
pub use self::vsock::*;
|
||||
pub use self::watchdog::*;
|
||||
pub use self::balloon::Balloon;
|
||||
pub use self::block::{Block, BlockState};
|
||||
pub use self::console::{Console, ConsoleResizer, Endpoint};
|
||||
pub use self::device::{
|
||||
DmaRemapping, UserspaceMapping, VirtioCommon, VirtioDevice, VirtioInterrupt,
|
||||
VirtioInterruptType, VirtioSharedMemoryList,
|
||||
};
|
||||
pub use self::epoll_helper::{
|
||||
EpollHelper, EpollHelperError, EpollHelperHandler, EPOLL_HELPER_EVENT_LAST,
|
||||
};
|
||||
pub use self::iommu::{AccessPlatformMapping, Iommu, IommuMapping};
|
||||
pub use self::mem::{BlocksState, Mem, VirtioMemMappingSource, VIRTIO_MEM_ALIGN_SIZE};
|
||||
pub use self::net::{Net, NetCtrlEpollHandler};
|
||||
pub use self::pmem::Pmem;
|
||||
pub use self::rng::Rng;
|
||||
pub use self::vdpa::{Vdpa, VdpaDmaMapping};
|
||||
pub use self::vsock::Vsock;
|
||||
pub use self::watchdog::Watchdog;
|
||||
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemory};
|
||||
use vm_virtio::VirtioDeviceType;
|
||||
|
||||
@@ -86,8 +91,8 @@ pub enum ActivateError {
|
||||
ThreadSpawn(std::io::Error),
|
||||
#[error("Failed to setup vhost-user-fs daemon: {0}")]
|
||||
VhostUserFsSetup(vhost_user::Error),
|
||||
#[error("Failed to setup vhost-user-blk daemon: {0}")]
|
||||
VhostUserBlkSetup(vhost_user::Error),
|
||||
#[error("Failed to setup vhost-user daemon: {0}")]
|
||||
VhostUserSetup(vhost_user::Error),
|
||||
#[error("Failed to create seccomp filter: {0}")]
|
||||
CreateSeccompFilter(seccompiler::Error),
|
||||
#[error("Failed to create rate limiter: {0}")]
|
||||
|
||||
@@ -259,6 +259,7 @@ fn virtio_thread_common() -> Vec<(i64, Vec<SeccompRule>)> {
|
||||
(libc::SYS_madvise, vec![]),
|
||||
(libc::SYS_mmap, vec![]),
|
||||
(libc::SYS_mprotect, vec![]),
|
||||
(libc::SYS_mremap, vec![]),
|
||||
(libc::SYS_munmap, vec![]),
|
||||
(libc::SYS_openat, vec![]),
|
||||
(libc::SYS_read, vec![]),
|
||||
|
||||
@@ -48,14 +48,13 @@ use super::pci_common_config::VirtioPciCommonConfigState;
|
||||
/// Vector value used to disable MSI for a queue.
|
||||
const VIRTQ_MSI_NO_VECTOR: u16 = 0xffff;
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum PciCapabilityType {
|
||||
CommonConfig = 1,
|
||||
NotifyConfig = 2,
|
||||
IsrConfig = 3,
|
||||
DeviceConfig = 4,
|
||||
PciConfig = 5,
|
||||
SharedMemoryConfig = 8,
|
||||
Common = 1,
|
||||
Notify = 2,
|
||||
Isr = 3,
|
||||
Device = 4,
|
||||
Pci = 5,
|
||||
SharedMemory = 8,
|
||||
}
|
||||
|
||||
// This offset represents the 2 bytes omitted from the VirtioPciCap structure
|
||||
@@ -210,7 +209,7 @@ impl PciCapability for VirtioPciCfgCap {
|
||||
impl VirtioPciCfgCap {
|
||||
fn new() -> Self {
|
||||
VirtioPciCfgCap {
|
||||
cap: VirtioPciCap::new(PciCapabilityType::PciConfig, 0, 0, 0),
|
||||
cap: VirtioPciCap::new(PciCapabilityType::Pci, 0, 0, 0),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -667,7 +666,7 @@ impl VirtioPciDevice {
|
||||
) -> std::result::Result<(), PciDeviceError> {
|
||||
// Add pointers to the different configuration structures from the PCI capabilities.
|
||||
let common_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::CommonConfig,
|
||||
PciCapabilityType::Common,
|
||||
settings_bar,
|
||||
COMMON_CONFIG_BAR_OFFSET as u32,
|
||||
COMMON_CONFIG_SIZE as u32,
|
||||
@@ -677,7 +676,7 @@ impl VirtioPciDevice {
|
||||
.map_err(PciDeviceError::CapabilitiesSetup)?;
|
||||
|
||||
let isr_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::IsrConfig,
|
||||
PciCapabilityType::Isr,
|
||||
settings_bar,
|
||||
ISR_CONFIG_BAR_OFFSET as u32,
|
||||
ISR_CONFIG_SIZE as u32,
|
||||
@@ -688,7 +687,7 @@ impl VirtioPciDevice {
|
||||
|
||||
// TODO(dgreid) - set based on device's configuration size?
|
||||
let device_cap = VirtioPciCap::new(
|
||||
PciCapabilityType::DeviceConfig,
|
||||
PciCapabilityType::Device,
|
||||
settings_bar,
|
||||
DEVICE_CONFIG_BAR_OFFSET as u32,
|
||||
DEVICE_CONFIG_SIZE as u32,
|
||||
@@ -698,7 +697,7 @@ impl VirtioPciDevice {
|
||||
.map_err(PciDeviceError::CapabilitiesSetup)?;
|
||||
|
||||
let notify_cap = VirtioPciNotifyCap::new(
|
||||
PciCapabilityType::NotifyConfig,
|
||||
PciCapabilityType::Notify,
|
||||
settings_bar,
|
||||
NOTIFICATION_BAR_OFFSET as u32,
|
||||
NOTIFICATION_SIZE as u32,
|
||||
@@ -1057,7 +1056,7 @@ impl PciDevice for VirtioPciDevice {
|
||||
|
||||
for (idx, shm) in shm_list.region_list.iter().enumerate() {
|
||||
let shm_cap = VirtioPciCap64::new(
|
||||
PciCapabilityType::SharedMemoryConfig,
|
||||
PciCapabilityType::SharedMemory,
|
||||
VIRTIO_SHM_BAR_INDEX as u8,
|
||||
idx as u8,
|
||||
shm.offset,
|
||||
|
||||
@@ -605,7 +605,7 @@ impl VirtioDevice for Fs {
|
||||
&mut self,
|
||||
shm_regions: VirtioSharedMemoryList,
|
||||
) -> std::result::Result<(), crate::Error> {
|
||||
if let Some(mut cache) = self.cache.as_mut() {
|
||||
if let Some(cache) = self.cache.as_mut() {
|
||||
cache.0 = shm_regions;
|
||||
Ok(())
|
||||
} else {
|
||||
|
||||
@@ -237,7 +237,7 @@ impl<S: VhostUserMasterReqHandler> VhostUserEpollHandler<S> {
|
||||
.map_err(|e| {
|
||||
EpollHelperError::IoError(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("failed reconnecting vhost-user backend{e:?}"),
|
||||
format!("failed reconnecting vhost-user backend: {e:?}"),
|
||||
))
|
||||
})?;
|
||||
|
||||
@@ -340,7 +340,7 @@ impl VhostUserCommon {
|
||||
&slave_req_handler,
|
||||
inflight.as_mut(),
|
||||
)
|
||||
.map_err(ActivateError::VhostUserBlkSetup)?;
|
||||
.map_err(ActivateError::VhostUserSetup)?;
|
||||
|
||||
Ok(VhostUserEpollHandler {
|
||||
vu: vu.clone(),
|
||||
@@ -413,7 +413,7 @@ impl VhostUserCommon {
|
||||
pub fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
if let Some(vu) = &self.vu {
|
||||
vu.lock().unwrap().pause_vhost_user().map_err(|e| {
|
||||
MigratableError::Pause(anyhow!("Error pausing vhost-user-blk backend: {:?}", e))
|
||||
MigratableError::Pause(anyhow!("Error pausing vhost-user backend: {:?}", e))
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
@@ -423,7 +423,7 @@ impl VhostUserCommon {
|
||||
pub fn resume(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
if let Some(vu) = &self.vu {
|
||||
vu.lock().unwrap().resume_vhost_user().map_err(|e| {
|
||||
MigratableError::Resume(anyhow!("Error resuming vhost-user-blk backend: {:?}", e))
|
||||
MigratableError::Resume(anyhow!("Error resuming vhost-user backend: {:?}", e))
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
/// The main job of `VsockConnection` is to forward data traffic, back and forth, between a
|
||||
/// guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while
|
||||
/// also managing its internal state.
|
||||
/// To that end, `VsockConnection` implements:
|
||||
/// - `VsockChannel` for:
|
||||
/// - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and
|
||||
/// - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and
|
||||
/// - updating its internal state, by absorbing control packets (anything other than
|
||||
/// VSOCK_OP_RW).
|
||||
/// - `VsockEpollListener` for getting notified about the availability of data or free buffer
|
||||
/// space at the host stream.
|
||||
///
|
||||
/// Note: there is a certain asymmetry to the RX and TX data flows:
|
||||
/// - RX transfers do not need any data buffering, since data is read straight from the
|
||||
/// host stream and into the guest-provided RX buffer;
|
||||
/// - TX transfers may require some data to be buffered by `VsockConnection`, if the host
|
||||
/// peer can't keep up with reading the data that we're writing. This is because, once
|
||||
/// the guest driver provides some data in a virtio TX buffer, the vsock device must
|
||||
/// consume it. If that data can't be forwarded straight to the host stream, we'll
|
||||
/// have to store it in a buffer (and flush it at a later time). Vsock flow control
|
||||
/// ensures that our TX buffer doesn't overflow.
|
||||
///
|
||||
//! The main job of `VsockConnection` is to forward data traffic, back and forth, between a
|
||||
//! guest-side AF_VSOCK socket and a host-side generic `Read + Write + AsRawFd` stream, while
|
||||
//! also managing its internal state.
|
||||
//! To that end, `VsockConnection` implements:
|
||||
//! - `VsockChannel` for:
|
||||
//! - moving data from the host stream to a guest-provided RX buffer, via `recv_pkt()`; and
|
||||
//! - moving data from a guest-provided TX buffer to the host stream, via `send_pkt()`; and
|
||||
//! - updating its internal state, by absorbing control packets (anything other than
|
||||
//! VSOCK_OP_RW).
|
||||
//! - `VsockEpollListener` for getting notified about the availability of data or free buffer
|
||||
//! space at the host stream.
|
||||
//!
|
||||
//! Note: there is a certain asymmetry to the RX and TX data flows:
|
||||
//! - RX transfers do not need any data buffering, since data is read straight from the
|
||||
//! host stream and into the guest-provided RX buffer;
|
||||
//! - TX transfers may require some data to be buffered by `VsockConnection`, if the host
|
||||
//! peer can't keep up with reading the data that we're writing. This is because, once
|
||||
//! the guest driver provides some data in a virtio TX buffer, the vsock device must
|
||||
//! consume it. If that data can't be forwarded straight to the host stream, we'll
|
||||
//! have to store it in a buffer (and flush it at a later time). Vsock flow control
|
||||
//! ensures that our TX buffer doesn't overflow.
|
||||
//
|
||||
// The code in this file is best read with a fresh memory of the vsock protocol inner-workings.
|
||||
// To help with that, here is a
|
||||
//
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
/// This module implements our vsock connection state machine. The heavy lifting is done by
|
||||
/// `connection::VsockConnection`, while this file only defines some constants and helper structs.
|
||||
///
|
||||
//! This module implements our vsock connection state machine. The heavy lifting is done by
|
||||
//! `connection::VsockConnection`, while this file only defines some constants and helper structs.
|
||||
|
||||
mod connection;
|
||||
mod txbuf;
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues.
|
||||
/// There are two components to a vsock packet, each using its own descriptor in a
|
||||
/// virtio queue:
|
||||
/// - the packet header; and
|
||||
/// - the packet data/buffer.
|
||||
/// There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds
|
||||
/// the header, and an optional second descriptor holds the data. The second descriptor is only
|
||||
/// present for data packets (VSOCK_OP_RW).
|
||||
///
|
||||
/// `VsockPacket` wraps these two buffers and provides direct access to the data stored
|
||||
/// in guest memory. This is done to avoid unnecessarily copying data from guest memory
|
||||
/// to temporary buffers, before passing it on to the vsock backend.
|
||||
///
|
||||
//! `VsockPacket` provides a thin wrapper over the buffers exchanged via virtio queues.
|
||||
//! There are two components to a vsock packet, each using its own descriptor in a
|
||||
//! virtio queue:
|
||||
//! - the packet header; and
|
||||
//! - the packet data/buffer.
|
||||
//! There is a 1:1 relation between descriptor chains and packets: the first (chain head) holds
|
||||
//! the header, and an optional second descriptor holds the data. The second descriptor is only
|
||||
//! present for data packets (VSOCK_OP_RW).
|
||||
//!
|
||||
//! `VsockPacket` wraps these two buffers and provides direct access to the data stored
|
||||
//! in guest memory. This is done to avoid unnecessarily copying data from guest memory
|
||||
//! to temporary buffers, before passing it on to the vsock backend.
|
||||
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
@@ -436,7 +436,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_tx_packet_assembly() {
|
||||
// Test case: successful TX packet assembly.
|
||||
{
|
||||
@@ -581,7 +580,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn test_packet_hdr_accessors() {
|
||||
const SRC_CID: u64 = 1;
|
||||
const DST_CID: u64 = 2;
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// This module implements the Unix Domain Sockets backend for vsock - a mediator between
|
||||
/// guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by
|
||||
/// `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for
|
||||
/// handling vsock connection states.
|
||||
/// Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend.
|
||||
///
|
||||
//! This module implements the Unix Domain Sockets backend for vsock - a mediator between
|
||||
//! guest-side AF_VSOCK sockets and host-side AF_UNIX sockets. The heavy lifting is performed by
|
||||
//! `muxer::VsockMuxer`, a connection multiplexer that uses `super::csm::VsockConnection` for
|
||||
//! handling vsock connection states.
|
||||
//!
|
||||
//! Check out `muxer.rs` for a more detailed explanation of the inner workings of this backend.
|
||||
|
||||
mod muxer;
|
||||
mod muxer_killq;
|
||||
mod muxer_rxq;
|
||||
|
||||
@@ -2,35 +2,42 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e.
|
||||
/// by implementing the `VsockBackend` trait, it abstracts away the gory details of translating
|
||||
/// between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock
|
||||
/// device model.
|
||||
///
|
||||
/// The vsock muxer has two main roles:
|
||||
/// 1. Vsock connection multiplexer:
|
||||
/// It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The
|
||||
/// muxer also routes packets to their owning connections. It does so via a connection
|
||||
/// `HashMap`, keyed by what is basically a (host_port, guest_port) tuple.
|
||||
/// Vsock packet traffic needs to be inspected, in order to detect connection request
|
||||
/// packets (leading to the creation of a new connection), and connection reset packets
|
||||
/// (leading to the termination of an existing connection). All other packets, though, must
|
||||
/// belong to an existing connection and, as such, the muxer simply forwards them.
|
||||
/// 2. Event dispatcher
|
||||
/// There are three event categories that the vsock backend is interested it:
|
||||
/// 1. A new host-initiated connection is ready to be accepted from the listening host Unix
|
||||
/// socket;
|
||||
/// 2. Data is available for reading from a newly-accepted host-initiated connection (i.e.
|
||||
/// the host is ready to issue a vsock connection request, informing us of the
|
||||
/// destination port to which it wants to connect);
|
||||
/// 3. Some event was triggered for a connected Unix socket, that belongs to a
|
||||
/// `VsockConnection`.
|
||||
/// The muxer gets notified about all of these events, because, as a `VsockEpollListener`
|
||||
/// implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
|
||||
/// other pollable FDs are then registered under this nested epoll FD.
|
||||
/// To route all these events to their handlers, the muxer uses another `HashMap` object,
|
||||
/// mapping `RawFd`s to `EpollListener`s.
|
||||
///
|
||||
//! `VsockMuxer` is the device-facing component of the Unix domain sockets vsock backend. I.e.
|
||||
//! by implementing the `VsockBackend` trait, it abstracts away the gory details of translating
|
||||
//! between AF_VSOCK and AF_UNIX, and presents a clean interface to the rest of the vsock
|
||||
//! device model.
|
||||
//!
|
||||
//! The vsock muxer has two main roles:
|
||||
//!
|
||||
//! ## Vsock connection multiplexer
|
||||
//!
|
||||
//! It's the muxer's job to create, manage, and terminate `VsockConnection` objects. The
|
||||
//! muxer also routes packets to their owning connections. It does so via a connection
|
||||
//! `HashMap`, keyed by what is basically a (host_port, guest_port) tuple.
|
||||
//!
|
||||
//! Vsock packet traffic needs to be inspected, in order to detect connection request
|
||||
//! packets (leading to the creation of a new connection), and connection reset packets
|
||||
//! (leading to the termination of an existing connection). All other packets, though, must
|
||||
//! belong to an existing connection and, as such, the muxer simply forwards them.
|
||||
//!
|
||||
//! ## Event dispatcher
|
||||
//!
|
||||
//! There are three event categories that the vsock backend is interested it:
|
||||
//! 1. A new host-initiated connection is ready to be accepted from the listening host Unix
|
||||
//! socket;
|
||||
//! 2. Data is available for reading from a newly-accepted host-initiated connection (i.e.
|
||||
//! the host is ready to issue a vsock connection request, informing us of the
|
||||
//! destination port to which it wants to connect);
|
||||
//! 3. Some event was triggered for a connected Unix socket, that belongs to a
|
||||
//! `VsockConnection`.
|
||||
//!
|
||||
//! The muxer gets notified about all of these events, because, as a `VsockEpollListener`
|
||||
//! implementor, it gets to register a nested epoll FD into the main VMM epolling loop. All
|
||||
//! other pollable FDs are then registered under this nested epoll FD.
|
||||
//!
|
||||
//! To route all these events to their handlers, the muxer uses another `HashMap` object,
|
||||
//! mapping `RawFd`s to `EpollListener`s.
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read};
|
||||
@@ -80,7 +87,7 @@ enum EpollListener {
|
||||
},
|
||||
/// A listener interested in new host-initiated connections.
|
||||
HostSock,
|
||||
/// A listener interested in reading host "connect <port>" commands from a freshly
|
||||
/// A listener interested in reading host "connect \<port>" commands from a freshly
|
||||
/// connected host socket.
|
||||
LocalStream(UnixStream),
|
||||
}
|
||||
@@ -106,7 +113,7 @@ pub struct VsockMuxer {
|
||||
/// The Unix socket, through which host-initiated connections are accepted.
|
||||
host_sock: UnixListener,
|
||||
/// The file system path of the host-side Unix socket. This is used to figure out the path
|
||||
/// to Unix sockets listening on specific ports. I.e. "<this path>_<port number>".
|
||||
/// to Unix sockets listening on specific ports. I.e. "\<this path>_\<port number>".
|
||||
host_sock_path: String,
|
||||
/// The nested epoll File, used to register epoll listeners.
|
||||
epoll_file: File,
|
||||
|
||||
@@ -2,29 +2,29 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced
|
||||
/// connection termination. I.e. after one peer issues a clean shutdown request
|
||||
/// (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in
|
||||
/// the near future (herein implemented via an expiring timer).
|
||||
///
|
||||
/// Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather
|
||||
/// an identifier - the connection key) to this queue. A subsequent pop() operation will
|
||||
/// succeed if and only if the first connection in the queue is ready to be terminated (i.e.
|
||||
/// its kill timer expired).
|
||||
///
|
||||
/// Without using this queue, the muxer would have to walk its entire connection pool
|
||||
/// (hashmap), whenever it needs to check for expired kill timers. With this queue, both
|
||||
/// scheduling and termination are performed in constant time. However, since we don't want to
|
||||
/// waste space on a kill queue that's as big as the connection hashmap itself, it is possible
|
||||
/// that this queue may become full at times. We call this kill queue "synchronized" if we are
|
||||
/// certain that all connections that are awaiting termination are present in the queue. This
|
||||
/// means a simple constant-time pop() operation is enough to check whether any connections
|
||||
/// need to be terminated. When the kill queue becomes full, though, pushing fails, so
|
||||
/// connections that should be terminated are left out. The queue is not synchronized anymore.
|
||||
/// When that happens, the muxer will first drain the queue, and then replace it with a new
|
||||
/// queue, created by walking the connection pool, looking for connections that will be
|
||||
/// expiring in the future.
|
||||
///
|
||||
//! `MuxerKillQ` implements a helper object that `VsockMuxer` can use for scheduling forced
|
||||
//! connection termination. I.e. after one peer issues a clean shutdown request
|
||||
//! (VSOCK_OP_SHUTDOWN), the concerned connection is queued for termination (VSOCK_OP_RST) in
|
||||
//! the near future (herein implemented via an expiring timer).
|
||||
//!
|
||||
//! Whenever the muxer needs to schedule a connection for termination, it pushes it (or rather
|
||||
//! an identifier - the connection key) to this queue. A subsequent pop() operation will
|
||||
//! succeed if and only if the first connection in the queue is ready to be terminated (i.e.
|
||||
//! its kill timer expired).
|
||||
//!
|
||||
//! Without using this queue, the muxer would have to walk its entire connection pool
|
||||
//! (hashmap), whenever it needs to check for expired kill timers. With this queue, both
|
||||
//! scheduling and termination are performed in constant time. However, since we don't want to
|
||||
//! waste space on a kill queue that's as big as the connection hashmap itself, it is possible
|
||||
//! that this queue may become full at times. We call this kill queue "synchronized" if we are
|
||||
//! certain that all connections that are awaiting termination are present in the queue. This
|
||||
//! means a simple constant-time pop() operation is enough to check whether any connections
|
||||
//! need to be terminated. When the kill queue becomes full, though, pushing fails, so
|
||||
//! connections that should be terminated are left out. The queue is not synchronized anymore.
|
||||
//! When that happens, the muxer will first drain the queue, and then replace it with a new
|
||||
//! queue, created by walking the connection pool, looking for connections that will be
|
||||
//! expiring in the future.
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::time::Instant;
|
||||
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
/// `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest)
|
||||
/// packets (or rather instructions on how to build said packets).
|
||||
///
|
||||
/// Under ideal operation, every connection, that has pending RX data, will be present in the muxer
|
||||
/// RX queue. However, since the RX queue is smaller than the connection pool, it may, under some
|
||||
/// conditions, become full, meaning that it can no longer account for all the connections that can
|
||||
/// yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the
|
||||
/// connection pool). A desynchronized RX queue still holds valid data, and the muxer will
|
||||
/// continue to pop packets from it. However, when a desynchronized queue is drained, additional
|
||||
/// data may still be available, so the muxer will have to perform a more costly walk of the entire
|
||||
/// connection pool to find it. This walk is performed here, as part of building an RX queue from
|
||||
/// the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to
|
||||
/// rebuild a synced one.
|
||||
///
|
||||
//! `MuxerRxQ` implements a helper object that `VsockMuxer` can use for queuing RX (host -> guest)
|
||||
//! packets (or rather instructions on how to build said packets).
|
||||
//!
|
||||
//! Under ideal operation, every connection, that has pending RX data, will be present in the muxer
|
||||
//! RX queue. However, since the RX queue is smaller than the connection pool, it may, under some
|
||||
//! conditions, become full, meaning that it can no longer account for all the connections that can
|
||||
//! yield RX data. When that happens, we say that it is no longer "synchronized" (i.e. with the
|
||||
//! connection pool). A desynchronized RX queue still holds valid data, and the muxer will
|
||||
//! continue to pop packets from it. However, when a desynchronized queue is drained, additional
|
||||
//! data may still be available, so the muxer will have to perform a more costly walk of the entire
|
||||
//! connection pool to find it. This walk is performed here, as part of building an RX queue from
|
||||
//! the connection pool. When an out-of-sync is drained, the muxer will discard it, and attempt to
|
||||
//! rebuild a synced one.
|
||||
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
use super::super::VsockChannel;
|
||||
|
||||
@@ -6,7 +6,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.139"
|
||||
vm-memory = "0.10.0"
|
||||
vm-memory = "0.11.0"
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies]
|
||||
arch = { path = "../arch" }
|
||||
|
||||
@@ -63,7 +63,6 @@ impl GsiAllocator {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[allow(clippy::new_without_default)]
|
||||
/// New GSI allocator
|
||||
pub fn new() -> Self {
|
||||
GsiAllocator {
|
||||
@@ -106,3 +105,10 @@ impl GsiAllocator {
|
||||
Ok(irq)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
impl Default for GsiAllocator {
|
||||
fn default() -> Self {
|
||||
GsiAllocator::new()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
mod address;
|
||||
mod gsi;
|
||||
/// page size related utility funtions
|
||||
pub mod page_size;
|
||||
mod system;
|
||||
|
||||
pub use crate::address::AddressAllocator;
|
||||
|
||||
38
vm-allocator/src/page_size.rs
Normal file
38
vm-allocator/src/page_size.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2023 Arm Limited (or its affiliates). All rights reserved.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use libc::{sysconf, _SC_PAGESIZE};
|
||||
|
||||
/// get host page size
|
||||
pub fn get_page_size() -> u64 {
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
unsafe { sysconf(_SC_PAGESIZE) as u64 }
|
||||
}
|
||||
|
||||
/// round up address to let it align page size
|
||||
pub fn align_page_size_up(address: u64) -> u64 {
|
||||
let page_size = get_page_size();
|
||||
(address + page_size - 1) & !(page_size - 1)
|
||||
}
|
||||
|
||||
/// round down address to let it align page size
|
||||
pub fn align_page_size_down(address: u64) -> u64 {
|
||||
let page_size = get_page_size();
|
||||
address & !(page_size - 1)
|
||||
}
|
||||
|
||||
/// Test if address is 4k aligned
|
||||
pub fn is_4k_aligned(address: u64) -> bool {
|
||||
(address & 0xfff) == 0
|
||||
}
|
||||
|
||||
/// Test if size is 4k aligned
|
||||
pub fn is_4k_multiple(size: u64) -> bool {
|
||||
(size & 0xfff) == 0
|
||||
}
|
||||
|
||||
/// Test if address is page size aligned
|
||||
pub fn is_page_size_aligned(address: u64) -> bool {
|
||||
let page_size = get_page_size();
|
||||
address & (page_size - 1) == 0
|
||||
}
|
||||
@@ -14,14 +14,7 @@ use crate::gsi::GsiAllocator;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::gsi::GsiApic;
|
||||
|
||||
use libc::{sysconf, _SC_PAGESIZE};
|
||||
|
||||
/// Safe wrapper for `sysconf(_SC_PAGESIZE)`.
|
||||
#[inline(always)]
|
||||
fn pagesize() -> usize {
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
unsafe { sysconf(_SC_PAGESIZE) as usize }
|
||||
}
|
||||
use crate::page_size::get_page_size;
|
||||
|
||||
/// Manages allocating system resources such as address space and interrupt numbers.
|
||||
///
|
||||
@@ -126,7 +119,7 @@ impl SystemAllocator {
|
||||
self.platform_mmio_address_space.allocate(
|
||||
address,
|
||||
size,
|
||||
Some(align_size.unwrap_or(pagesize() as u64)),
|
||||
Some(align_size.unwrap_or(get_page_size())),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,7 +133,7 @@ impl SystemAllocator {
|
||||
self.mmio_hole_address_space.allocate(
|
||||
address,
|
||||
size,
|
||||
Some(align_size.unwrap_or(pagesize() as u64)),
|
||||
Some(align_size.unwrap_or(get_page_size())),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ kvm = ["vfio-ioctls/kvm"]
|
||||
mshv = ["vfio-ioctls/mshv"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
anyhow = "1.0.71"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
thiserror = "1.0.38"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
thiserror = "1.0.40"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap"] }
|
||||
vmm-sys-util = "0.11.0"
|
||||
|
||||
|
||||
@@ -110,8 +110,7 @@ impl Bus {
|
||||
let devices = self.devices.read().unwrap();
|
||||
let (range, dev) = devices
|
||||
.range(..=BusRange { base: addr, len: 1 })
|
||||
.rev()
|
||||
.next()?;
|
||||
.next_back()?;
|
||||
dev.upgrade().map(|d| (*range, d.clone()))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
thiserror = "1.0.38"
|
||||
serde = { version = "1.0.151", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.93"
|
||||
versionize = "0.1.9"
|
||||
anyhow = "1.0.71"
|
||||
thiserror = "1.0.40"
|
||||
serde = { version = "1.0.164", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.96"
|
||||
versionize = "0.1.10"
|
||||
versionize_derive = "0.1.4"
|
||||
vm-memory = { version = "0.10.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
vm-memory = { version = "0.11.0", features = ["backend-mmap", "backend-atomic"] }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user