mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
Compare commits
486 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
446d2c89d9 | ||
|
|
d6895188b1 | ||
|
|
e2e070ad8a | ||
|
|
6aa10938e4 | ||
|
|
7936bfe680 | ||
|
|
29b522e464 | ||
|
|
da6df6bddf | ||
|
|
b4dd3a52c5 | ||
|
|
4ff11f5dfa | ||
|
|
40faac3d85 | ||
|
|
cbf5068e17 | ||
|
|
2c3908eed9 | ||
|
|
8ba1bc7621 | ||
|
|
8d11ba4833 | ||
|
|
273098ee99 | ||
|
|
84f1377903 | ||
|
|
9592accb46 | ||
|
|
a25b49e80c | ||
|
|
b0324f8557 | ||
|
|
faa632feaa | ||
|
|
421e51fb55 | ||
|
|
71370d7e15 | ||
|
|
8458696094 | ||
|
|
4cc44f8cc7 | ||
|
|
846bd3a504 | ||
|
|
c11d430651 | ||
|
|
9978aac402 | ||
|
|
082872423f | ||
|
|
b869e65e7e | ||
|
|
04bfb3d93e | ||
|
|
acafda6739 | ||
|
|
6db3d89837 | ||
|
|
7c965538a6 | ||
|
|
f254f11b48 | ||
|
|
18d51d3bd1 | ||
|
|
70a3564a5e | ||
|
|
128d0984a2 | ||
|
|
5e3d72671b | ||
|
|
60d805771b | ||
|
|
3f4cbce900 | ||
|
|
5343e09e7b | ||
|
|
7dc9259c6c | ||
|
|
e7a0d6b4e4 | ||
|
|
fdda680eb4 | ||
|
|
d744ce10ef | ||
|
|
4552d07a80 | ||
|
|
ec7d4e727a | ||
|
|
9cbb94b6d9 | ||
|
|
6c1fe07d90 | ||
|
|
92a8fbbff8 | ||
|
|
f2dfb44d5c | ||
|
|
9d1985111a | ||
|
|
a4b478b96a | ||
|
|
3069ce9f2d | ||
|
|
c35220b1ca | ||
|
|
ece4fc2026 | ||
|
|
05769879dd | ||
|
|
28413d26db | ||
|
|
a08da07d2a | ||
|
|
00fbd77494 | ||
|
|
23fb4fa26d | ||
|
|
8846409eab | ||
|
|
020b64a9ef | ||
|
|
c504f302e9 | ||
|
|
ceb43fae6d | ||
|
|
2451c4d833 | ||
|
|
23bb629241 | ||
|
|
bae63a8b8c | ||
|
|
2f430e08e1 | ||
|
|
f1c4705638 | ||
|
|
a2a492f3df | ||
|
|
f452e51488 | ||
|
|
9f111388c0 | ||
|
|
9f27954fbd | ||
|
|
603ca0e21b | ||
|
|
7c6bdf8804 | ||
|
|
afb1c761ec | ||
|
|
271bacc4ef | ||
|
|
17722ada51 | ||
|
|
3a6df69d45 | ||
|
|
a116add991 | ||
|
|
dd77070f16 | ||
|
|
df86d4c50f | ||
|
|
81d53c5711 | ||
|
|
3844bd20d1 | ||
|
|
a6cd2e10c1 | ||
|
|
0fc3fad363 | ||
|
|
bf6920f774 | ||
|
|
28d6bff340 | ||
|
|
0fa31539eb | ||
|
|
297459087a | ||
|
|
8cf3de3c85 | ||
|
|
97f5b68424 | ||
|
|
2861330d09 | ||
|
|
55b8a2182b | ||
|
|
b1f61d7286 | ||
|
|
7e22786b2c | ||
|
|
eade9d8b87 | ||
|
|
1a5b94ee0e | ||
|
|
2805e7b1dc | ||
|
|
3593055e77 | ||
|
|
5447451921 | ||
|
|
b2bf88bcb1 | ||
|
|
75fbea3c46 | ||
|
|
e3bb822c4e | ||
|
|
9acb69f3e3 | ||
|
|
4c4eb8db40 | ||
|
|
6daddf0831 | ||
|
|
5d55070ceb | ||
|
|
0ac094c0d1 | ||
|
|
cb844ecd1d | ||
|
|
a3dfe726f8 | ||
|
|
9aab70ec1a | ||
|
|
dfcb0a192a | ||
|
|
8c19d526cd | ||
|
|
580bab6008 | ||
|
|
46d6a6cdfd | ||
|
|
b7512d3d83 | ||
|
|
51c5ba9610 | ||
|
|
09e21e8fe5 | ||
|
|
d27316dab6 | ||
|
|
98bbfa9738 | ||
|
|
36852795e4 | ||
|
|
6f571d5c07 | ||
|
|
5bd305fa4f | ||
|
|
d650c684f1 | ||
|
|
458ae2c5be | ||
|
|
1025783973 | ||
|
|
411b8b3a96 | ||
|
|
0862064fd2 | ||
|
|
e41fe0acae | ||
|
|
a7024074c0 | ||
|
|
a50c10bdf9 | ||
|
|
b806935941 | ||
|
|
1cf73c83e2 | ||
|
|
dc91866b56 | ||
|
|
6b915de2e0 | ||
|
|
1a17564ee9 | ||
|
|
c9c031a425 | ||
|
|
0ab4097606 | ||
|
|
f1151cb55e | ||
|
|
9b0bd71154 | ||
|
|
1603841f91 | ||
|
|
9c6e7c4a4b | ||
|
|
0ee8ead53d | ||
|
|
5fd49927f2 | ||
|
|
80c34bd756 | ||
|
|
76d3d3d505 | ||
|
|
f16fe56e33 | ||
|
|
d9eff12ba3 | ||
|
|
42b5d4a2f7 | ||
|
|
200b13517b | ||
|
|
07d78e6a12 | ||
|
|
1659a0cb6f | ||
|
|
6b44f0d12a | ||
|
|
5752a2a4fb | ||
|
|
5d2db68f67 | ||
|
|
b780a916bb | ||
|
|
16782e8c6d | ||
|
|
bd024bffb1 | ||
|
|
ddef99a0ff | ||
|
|
1591cae440 | ||
|
|
ea4ab9a4cc | ||
|
|
55479a64d2 | ||
|
|
d0789871a5 | ||
|
|
57184f110a | ||
|
|
20b9f95afd | ||
|
|
6994b33a24 | ||
|
|
da20fa74c6 | ||
|
|
384752647a | ||
|
|
052f38fa96 | ||
|
|
414e8e068b | ||
|
|
c325aa3297 | ||
|
|
db5d74cb26 | ||
|
|
3982a2af0f | ||
|
|
072114d7c5 | ||
|
|
5e19422fcf | ||
|
|
26d1a76ad9 | ||
|
|
e864e35c29 | ||
|
|
8c170570c4 | ||
|
|
10676b74dc | ||
|
|
6717ac0cf2 | ||
|
|
df38ef56be | ||
|
|
747003d33c | ||
|
|
5ec693aa2a | ||
|
|
52e2286916 | ||
|
|
507912385a | ||
|
|
b552aebbd4 | ||
|
|
85f5364594 | ||
|
|
7f987552ef | ||
|
|
a3a175216a | ||
|
|
7a3d8c6299 | ||
|
|
832f09a075 | ||
|
|
2f0073544a | ||
|
|
3c421593c3 | ||
|
|
2198baa547 | ||
|
|
7b93a8dd78 | ||
|
|
1bd30dc69f | ||
|
|
e5bc5e632d | ||
|
|
5cdb284db2 | ||
|
|
4c23f38759 | ||
|
|
b3ca1d90e9 | ||
|
|
a45e458c50 | ||
|
|
a061bc32e4 | ||
|
|
71148e1fa5 | ||
|
|
41f2f41ed2 | ||
|
|
8a066466ed | ||
|
|
9c759463c3 | ||
|
|
424efe6c69 | ||
|
|
bea100707f | ||
|
|
ac00838f34 | ||
|
|
e9b8126cf7 | ||
|
|
e575582dfa | ||
|
|
804bad53df | ||
|
|
0dafd47a7c | ||
|
|
9bd1ece9cf | ||
|
|
e9eb2c5dbc | ||
|
|
4e46a1bc3c | ||
|
|
400c28fa58 | ||
|
|
b9d6cbf5f6 | ||
|
|
e0f794f8ba | ||
|
|
6cbe08fa40 | ||
|
|
8f74bd5bd2 | ||
|
|
77df4e6773 | ||
|
|
c99d637693 | ||
|
|
8eed276d14 | ||
|
|
8759c3db3e | ||
|
|
e2225bb4b0 | ||
|
|
09f5b82fd7 | ||
|
|
7731d2f1be | ||
|
|
4becb11a44 | ||
|
|
ce984b73f5 | ||
|
|
3e1ce98d1a | ||
|
|
75b9e70ec8 | ||
|
|
7d09df468d | ||
|
|
f29f3085ed | ||
|
|
ce6446501d | ||
|
|
5ee0291ddc | ||
|
|
6672334abc | ||
|
|
24b6def951 | ||
|
|
4253192ffc | ||
|
|
eee10b4b01 | ||
|
|
34c5116883 | ||
|
|
8fc3b970cd | ||
|
|
816bf3abf0 | ||
|
|
de3e003e3e | ||
|
|
d3081ff50c | ||
|
|
ef9a388f87 | ||
|
|
74dabf5b90 | ||
|
|
5d80084868 | ||
|
|
284b616738 | ||
|
|
b85c5faafc | ||
|
|
d71f073af3 | ||
|
|
1c1472b88a | ||
|
|
6e4eb01c20 | ||
|
|
3adc654680 | ||
|
|
bbcb4bc828 | ||
|
|
1ee801450e | ||
|
|
365e4e6bc2 | ||
|
|
8d5b4f9707 | ||
|
|
f57a04830c | ||
|
|
25ce38bee1 | ||
|
|
5847e73f40 | ||
|
|
53caa565bb | ||
|
|
db5583d6a3 | ||
|
|
1ed49a2306 | ||
|
|
e9b069bf38 | ||
|
|
8f4aa07a80 | ||
|
|
5462fd810c | ||
|
|
81c5855184 | ||
|
|
53060874a7 | ||
|
|
9bcb984962 | ||
|
|
ae68c2f31a | ||
|
|
1f5e2a38a7 | ||
|
|
cf1c64171a | ||
|
|
9fe33890f8 | ||
|
|
7b9a110540 | ||
|
|
2acb50f752 | ||
|
|
ea0729c016 | ||
|
|
cdc14815be | ||
|
|
4fda4ad6c9 | ||
|
|
95ca79974a | ||
|
|
eb5c5f2c7f | ||
|
|
85bbf75fe8 | ||
|
|
b4566b9eab | ||
|
|
e2a8a1483f | ||
|
|
ea60d48853 | ||
|
|
658658e76c | ||
|
|
b7b3b45364 | ||
|
|
d5b4d0d951 | ||
|
|
1c18d124dc | ||
|
|
7a42ce9310 | ||
|
|
1db7718589 | ||
|
|
cf68f03ab6 | ||
|
|
4ecc778efe | ||
|
|
48ba999bd9 | ||
|
|
ef05354c81 | ||
|
|
277cfd07ba | ||
|
|
4f05b8463c | ||
|
|
c9983ff4ad | ||
|
|
714b529bb2 | ||
|
|
99bcebad74 | ||
|
|
22d86fb6d2 | ||
|
|
2eed24b4b2 | ||
|
|
be7829b752 | ||
|
|
ea2685e928 | ||
|
|
14ba3f68d3 | ||
|
|
779bc1a53a | ||
|
|
8b8daf571a | ||
|
|
482e1ca435 | ||
|
|
a61302f73f | ||
|
|
33fd0af8b3 | ||
|
|
cb243571de | ||
|
|
70f7f64e23 | ||
|
|
88952cc500 | ||
|
|
715a7d9065 | ||
|
|
1676fffaad | ||
|
|
1daef5e8c9 | ||
|
|
735658a49d | ||
|
|
b95e46565c | ||
|
|
eeba1d3ad8 | ||
|
|
271e17bd79 | ||
|
|
b9c260c0de | ||
|
|
6e78ac1837 | ||
|
|
dad5af612b | ||
|
|
101d403a6b | ||
|
|
29e3fefc3d | ||
|
|
859f72b5a5 | ||
|
|
8155be2e6b | ||
|
|
4577e5050b | ||
|
|
1952405f69 | ||
|
|
1dc913427c | ||
|
|
0a97b76c52 | ||
|
|
b204f43aae | ||
|
|
ade8d71264 | ||
|
|
92b8bdf474 | ||
|
|
84e2f6c1da | ||
|
|
e02f5c9699 | ||
|
|
2f492fbe36 | ||
|
|
c47cb868ec | ||
|
|
fb1755d85d | ||
|
|
5e1e523a90 | ||
|
|
685ca03e67 | ||
|
|
b80feb3d96 | ||
|
|
cb15ae5462 | ||
|
|
6738e45b37 | ||
|
|
c2f133990d | ||
|
|
a926bc139b | ||
|
|
5b05e0cdcd | ||
|
|
e7a2a715e0 | ||
|
|
430f72f96c | ||
|
|
901f65388a | ||
|
|
68e95d5841 | ||
|
|
c5f20c45a0 | ||
|
|
c7d1cfbd88 | ||
|
|
9c8f291b60 | ||
|
|
70af81d755 | ||
|
|
8fa3864ae8 | ||
|
|
221c1f1bdc | ||
|
|
3baebc1af0 | ||
|
|
2563b08ff0 | ||
|
|
f6333a39a5 | ||
|
|
936237d4d6 | ||
|
|
6408e8629e | ||
|
|
617b568f71 | ||
|
|
0fcbcea275 | ||
|
|
10d1922393 | ||
|
|
0162d73ed8 | ||
|
|
d57c49664f | ||
|
|
2f46647ecc | ||
|
|
9ef1187f4a | ||
|
|
e7db354c27 | ||
|
|
6ba5b0a83a | ||
|
|
2c59702e4a | ||
|
|
98ba347956 | ||
|
|
cd0aca4bcd | ||
|
|
f27cbb9caf | ||
|
|
e4763b47f1 | ||
|
|
7cc1643782 | ||
|
|
58501ed0a6 | ||
|
|
b72136ddb3 | ||
|
|
07756aa8fb | ||
|
|
c47ab55e99 | ||
|
|
a749063c8a | ||
|
|
cf2abd35d0 | ||
|
|
0dbff2a81d | ||
|
|
e355bb9fd4 | ||
|
|
aeaf432784 | ||
|
|
ccc9308ec1 | ||
|
|
129f708df7 | ||
|
|
542f05ebfa | ||
|
|
8e89a10db7 | ||
|
|
5283cb38db | ||
|
|
346bee48ad | ||
|
|
210a29f05c | ||
|
|
21a21ce51a | ||
|
|
877a537bf7 | ||
|
|
5a1e9c9bff | ||
|
|
a45939fb40 | ||
|
|
b85d29780f | ||
|
|
b3351e11b3 | ||
|
|
05720dbf25 | ||
|
|
d7ba8ad1fa | ||
|
|
748611752d | ||
|
|
9c5636204d | ||
|
|
fbbbd04ddf | ||
|
|
89af7dcb2b | ||
|
|
8737ca4d45 | ||
|
|
d186297dba | ||
|
|
09d6cdb185 | ||
|
|
c40c1778e5 | ||
|
|
58a2abbba2 | ||
|
|
b6159217b6 | ||
|
|
7bb828ecf2 | ||
|
|
4a47cdcebd | ||
|
|
8813456aef | ||
|
|
6c8bd1f476 | ||
|
|
6a76a6772d | ||
|
|
cbc388c7e2 | ||
|
|
4773e23c77 | ||
|
|
3b0d278ba3 | ||
|
|
443b64b04f | ||
|
|
ccccc94c8a | ||
|
|
3f0a33a50f | ||
|
|
32aedddb0a | ||
|
|
fa15cf6ac3 | ||
|
|
5c12c15f26 | ||
|
|
bde81405a8 | ||
|
|
9742fa5c7c | ||
|
|
3806afdc43 | ||
|
|
c6ba188586 | ||
|
|
afe386bc13 | ||
|
|
df21e15148 | ||
|
|
2883c71911 | ||
|
|
07a78842b5 | ||
|
|
91c7590ba6 | ||
|
|
e1b0630b79 | ||
|
|
2a2cea1658 | ||
|
|
3cd02403db | ||
|
|
a9f5021005 | ||
|
|
f14d0d0191 | ||
|
|
4959434219 | ||
|
|
7444c3a0c5 | ||
|
|
35d3c1f611 | ||
|
|
be5fd7c572 | ||
|
|
39172f8b54 | ||
|
|
2bcf718028 | ||
|
|
6d047bdec6 | ||
|
|
c6e534baf7 | ||
|
|
fb2b633ada | ||
|
|
8fb64859cc | ||
|
|
254d648bb7 | ||
|
|
21b0ab106c | ||
|
|
7bce72dff3 | ||
|
|
50f5f43ae3 | ||
|
|
fd3cf761be | ||
|
|
0a04c7206d | ||
|
|
58d3d4c34e | ||
|
|
eea2907daf | ||
|
|
7b5e8a3ca8 | ||
|
|
616d01aca2 | ||
|
|
637dc53a48 | ||
|
|
4b9b52fc6f | ||
|
|
3d1cfd4d55 | ||
|
|
e1c09b66ba | ||
|
|
af770c814b | ||
|
|
a29e53e436 | ||
|
|
00bb1ea1d5 | ||
|
|
bb6c93d5df | ||
|
|
90df54a245 | ||
|
|
ca9a42ece8 | ||
|
|
2f8540da70 | ||
|
|
07bef815cc | ||
|
|
e1151482fc | ||
|
|
3e536f91eb | ||
|
|
cab0b3446f | ||
|
|
7bb343dce8 | ||
|
|
9b0fe505ca | ||
|
|
03a606c7ec | ||
|
|
c452471c4e | ||
|
|
882cdda995 | ||
|
|
788d77aee5 | ||
|
|
e08c747638 | ||
|
|
b519975fc8 | ||
|
|
348def9dfb | ||
|
|
b09cbb8493 |
4
.github/workflows/build.yaml
vendored
4
.github/workflows/build.yaml
vendored
@@ -13,6 +13,7 @@ jobs:
|
|||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
- nightly
|
- nightly
|
||||||
|
- 1.54
|
||||||
target:
|
target:
|
||||||
- x86_64-unknown-linux-gnu
|
- x86_64-unknown-linux-gnu
|
||||||
- x86_64-unknown-linux-musl
|
- x86_64-unknown-linux-musl
|
||||||
@@ -22,6 +23,9 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install musl-gcc
|
||||||
|
run: sudo apt install -y musl-tools
|
||||||
|
|
||||||
- name: Install Rust toolchain (${{ matrix.rust }})
|
- name: Install Rust toolchain (${{ matrix.rust }})
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
15
.github/workflows/docker-image.yaml
vendored
15
.github/workflows/docker-image.yaml
vendored
@@ -27,6 +27,17 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
# list of Docker images to use as base name for tags
|
||||||
|
images: cloudhypervisor/dev
|
||||||
|
# generate Docker tags based on the following events/attributes
|
||||||
|
tags: |
|
||||||
|
type=raw,value={{date 'YYYYMMDD'}}-0
|
||||||
|
type=sha
|
||||||
|
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
if: ${{ github.event_name == 'push' }}
|
if: ${{ github.event_name == 'push' }}
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
@@ -34,7 +45,7 @@ jobs:
|
|||||||
file: ./resources/Dockerfile
|
file: ./resources/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: cloudhypervisor/dev:latest
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
|
||||||
- name: Build only
|
- name: Build only
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
@@ -42,7 +53,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
file: ./resources/Dockerfile
|
file: ./resources/Dockerfile
|
||||||
platforms: linux/amd64,linux/arm64
|
platforms: linux/amd64,linux/arm64
|
||||||
tags: cloudhypervisor/dev:latest
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
run: echo ${{ steps.docker_build.outputs.digest }}
|
run: echo ${{ steps.docker_build.outputs.digest }}
|
||||||
|
|||||||
2
.github/workflows/quality.yaml
vendored
2
.github/workflows/quality.yaml
vendored
@@ -55,7 +55,7 @@ jobs:
|
|||||||
run: cargo clippy --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings
|
run: cargo clippy --all --all-targets --no-default-features --tests --features "mshv" -- -D warnings
|
||||||
|
|
||||||
- name: Clippy (integration tests)
|
- name: Clippy (integration tests)
|
||||||
run: cargo clippy --all --all-targets --tests --features "integration_tests" -- -D warnings
|
run: cargo clippy --all --all-targets --tests -- -D warnings
|
||||||
|
|
||||||
- name: Check build did not modify any files
|
- name: Check build did not modify any files
|
||||||
run: test -z "$(git status --porcelain)"
|
run: test -z "$(git status --porcelain)"
|
||||||
|
|||||||
12
.github/workflows/release.yaml
vendored
12
.github/workflows/release.yaml
vendored
@@ -9,6 +9,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Code checkout
|
- name: Code checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
- name: Install musl-gcc
|
||||||
|
run: sudo apt install -y musl-tools
|
||||||
- name: Create release directory
|
- name: Create release directory
|
||||||
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
run: rsync -rv --exclude=.git . ../cloud-hypervisor-${{ github.event.ref }}
|
||||||
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
- name: Install Rust toolchain (x86_64-unknown-linux-gnu)
|
||||||
@@ -99,6 +101,16 @@ jobs:
|
|||||||
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
asset_path: target/x86_64-unknown-linux-gnu/release/ch-remote
|
||||||
asset_name: ch-remote
|
asset_name: ch-remote
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
- name: Upload static-ch-remote
|
||||||
|
id: upload-release-static-ch-remote
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||||
|
asset_path: target/x86_64-unknown-linux-musl/release/ch-remote
|
||||||
|
asset_name: ch-remote-static
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
- name: Upload static AArch64 cloud-hypervisor
|
- name: Upload static AArch64 cloud-hypervisor
|
||||||
id: upload-release-static-aarch64-cloud-hypervisor
|
id: upload-release-static-aarch64-cloud-hypervisor
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
/build
|
/build
|
||||||
|
/.cargo
|
||||||
/target
|
/target
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
**/Cargo.lock
|
**/Cargo.lock
|
||||||
|
|||||||
446
Cargo.lock
generated
446
Cargo.lock
generated
@@ -9,21 +9,6 @@ dependencies = [
|
|||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "addr2line"
|
|
||||||
version = "0.17.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
|
||||||
dependencies = [
|
|
||||||
"gimli",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "adler"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
@@ -33,20 +18,11 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.51"
|
version = "1.0.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api_client"
|
name = "api_client"
|
||||||
@@ -97,24 +73,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.63"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6"
|
|
||||||
dependencies = [
|
|
||||||
"addr2line",
|
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"miniz_oxide",
|
|
||||||
"object",
|
|
||||||
"rustc-demangle",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
@@ -158,9 +119,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.72"
|
version = "1.0.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -170,29 +131,29 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.34.0"
|
version = "3.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"os_str_bytes",
|
||||||
"strsim",
|
"strsim",
|
||||||
"term_size",
|
"termcolor",
|
||||||
|
"terminal_size",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
|
||||||
"vec_map",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "20.0.0"
|
version = "22.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
"clap",
|
"clap",
|
||||||
"credibility",
|
"dirs",
|
||||||
"dirs 4.0.0",
|
|
||||||
"epoll",
|
"epoll",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
@@ -214,9 +175,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32c"
|
name = "crc32c"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
@@ -227,16 +188,6 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
checksum = "55626594feae15d266d52440b26ff77de0e22230cf0c113abe619084c1ddc910"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "credibility"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "fae7a162fd5b462bc49704873a89950a655d44161add4be07e00e64c4c83a5bf"
|
|
||||||
dependencies = [
|
|
||||||
"failure",
|
|
||||||
"failure_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "devices"
|
name = "devices"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -257,15 +208,6 @@ dependencies = [
|
|||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "dirs"
|
|
||||||
version = "3.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309"
|
|
||||||
dependencies = [
|
|
||||||
"dirs-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@@ -319,28 +261,6 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "failure"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace",
|
|
||||||
"failure_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "failure_derive"
|
|
||||||
version = "0.1.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
"synstructure",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdt"
|
name = "fdt"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
@@ -348,22 +268,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "gdbstub"
|
||||||
version = "0.2.3"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"log",
|
||||||
|
"managed",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdbstub_arch"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
|
||||||
|
dependencies = [
|
||||||
|
"gdbstub",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "gimli"
|
|
||||||
version = "0.26.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -371,10 +309,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hashbrown"
|
||||||
version = "0.1.19"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -409,14 +353,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced-x86"
|
name = "iced-x86"
|
||||||
version = "1.15.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
|
checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instant"
|
name = "instant"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@@ -447,14 +401,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.8"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
|
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0-tdx#52e56d0e8ef0f6ea32fc0492e6a175b73617a49f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@@ -464,8 +418,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-ioctls"
|
name = "kvm-ioctls"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
|
||||||
checksum = "97422ba48d7ffb66fd4d18130f72ab66f9bbbf791fb7a87b9291cdcfec437593"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -480,9 +433,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.108"
|
version = "0.2.119"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libssh2-sys"
|
name = "libssh2-sys"
|
||||||
@@ -521,9 +474,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
version = "0.4.5"
|
version = "0.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109"
|
checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"scopeguard",
|
"scopeguard",
|
||||||
]
|
]
|
||||||
@@ -537,6 +490,12 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "managed"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
@@ -546,26 +505,16 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#0a58eb1ece68e326e68365c4297d0a7c08ecd9bc"
|
source = "git+https://github.com/firecracker-microvm/micro-http?branch=main#a730d86940081ad044cdfbc1285c1db6d3048392"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miniz_oxide"
|
|
||||||
version = "0.4.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
|
||||||
dependencies = [
|
|
||||||
"adler",
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-bindings"
|
name = "mshv-bindings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#8770516859e7d05193c496b77ac5ddad3ca5943a"
|
source = "git+https://github.com/rust-vmm/mshv?branch=main#d241ffcacdfa4240b4a1d34b44af89dc7b113986"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -577,7 +526,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-ioctls"
|
name = "mshv-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/mshv?branch=main#8770516859e7d05193c496b77ac5ddad3ca5943a"
|
source = "git+https://github.com/rust-vmm/mshv?branch=main#d241ffcacdfa4240b4a1d34b44af89dc7b113986"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"mshv-bindings",
|
"mshv-bindings",
|
||||||
@@ -615,23 +564,33 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "num-traits"
|
||||||
version = "0.27.1"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "111.17.0+1.1.1m"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.71"
|
version = "0.9.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
|
checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@@ -640,6 +599,15 @@ dependencies = [
|
|||||||
name = "option_parser"
|
name = "option_parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.11.2"
|
version = "0.11.2"
|
||||||
@@ -665,6 +633,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pci"
|
name = "pci"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -674,6 +648,8 @@ dependencies = [
|
|||||||
"hypervisor",
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -687,17 +663,31 @@ dependencies = [
|
|||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "performance-metrics"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"dirs",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"test_infra",
|
||||||
|
"thiserror",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.22"
|
version = "0.3.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
|
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet"
|
name = "pnet"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b6d2a0409666964722368ef5fb74b9f93fac11c18bef3308693c16c6733f103"
|
checksum = "8750e073f82219c01e771133c64718d7685aef922da8a0d430a46aed05b6341a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
@@ -709,15 +699,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_base"
|
name = "pnet_base"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25488cd551a753dcaaa6fffc9f69a7610a412dd8954425bf7ffad5f7d1156fb8"
|
checksum = "8205fe084bd43a3af79b3155c19feddd62e733640498842e631a2ffe107d1538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_datalink"
|
name = "pnet_datalink"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4d1f8ab1ef6c914cf51dc5dfe0be64088ea5f3b08bbf5a31abc70356d271198"
|
checksum = "6f85aef5e52e22ff06b1b11f2eb6d52959a9e0ecad3cb3f5cc2d78cadc077f0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -728,9 +718,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_macros"
|
name = "pnet_macros"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30490e0852e58402b8fae0d39897b08a24f493023a4d6cf56b2e30f31ed57548"
|
checksum = "98cc3af95fed6dc318dfede3e81320f96ad5e237c6f7c4688108b19c8e67432d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -740,18 +730,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_macros_support"
|
name = "pnet_macros_support"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4714e10f30cab023005adce048f2d30dd4ac4f093662abf2220855655ef8f90"
|
checksum = "feaba58ba96abb218ec584d6caf0d3ff48922df05dbbeb1560553c197091b29e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_packet"
|
name = "pnet_packet"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8588067671d03c9f4254b2e66fecb4d8b93b5d3e703195b84f311cd137e32130"
|
checksum = "f246edaaf1aaf82072d4cd38ee18bcc5dfc0464093f9ca39e4ac5962d68cf9d4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"glob",
|
"glob",
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
@@ -761,9 +751,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_sys"
|
name = "pnet_sys"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9a3f32b0df45515befd19eed04616f6b56a488da92afc61164ef455e955f07f"
|
checksum = "028c87a5e3a48fc07df099a2025f2ef16add5993712e1494ba69a6707ee7ed06"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -771,9 +761,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pnet_transport"
|
name = "pnet_transport"
|
||||||
version = "0.28.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "932b2916d693bcc5fa18443dc99142e0a6fd31a6ce75a511868f7174c17e2bce"
|
checksum = "950f2a7961e19d22e19e84ff0a6e0955013185fe149673499662633d02b41b7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"pnet_base",
|
"pnet_base",
|
||||||
@@ -783,9 +773,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
@@ -803,9 +793,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.10"
|
version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -821,9 +811,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -866,26 +856,20 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc-demangle"
|
|
||||||
version = "0.1.21"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.2.3"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.6"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
@@ -904,30 +888,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
|
||||||
dependencies = [
|
|
||||||
"semver-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.130"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.130"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -936,9 +911,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.72"
|
version = "1.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -947,9 +922,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.10"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -966,9 +941,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh2"
|
name = "ssh2"
|
||||||
@@ -990,15 +965,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.82"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1018,30 +993,31 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term_size"
|
name = "termcolor"
|
||||||
version = "0.3.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "termcolor"
|
|
||||||
version = "1.1.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "test_infra"
|
name = "test_infra"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 3.0.2",
|
"dirs",
|
||||||
"epoll",
|
"epoll",
|
||||||
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"ssh2",
|
"ssh2",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1050,12 +1026,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"term_size",
|
"terminal_size",
|
||||||
"unicode-width",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1078,12 +1053,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -1105,12 +1074,6 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "versionize"
|
name = "versionize"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -1140,9 +1103,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-bindings"
|
name = "vfio-bindings"
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
|
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
@@ -1150,7 +1113,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-ioctls"
|
name = "vfio-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#19e5b83ddfad430109ce3e8d51f4a24796099127"
|
source = "git+https://github.com/rust-vmm/vfio?branch=main#f75a77c1ab6349c105bc1462a65508726b4c2e0f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
@@ -1197,9 +1160,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost"
|
name = "vhost"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1208,17 +1171,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost_user_backend"
|
name = "vhost-user-backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rust-vmm/vhost-user-backend?branch=main#bbc892ba4526bdf8101252f7aa51832d1f2eeabd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"epoll",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"vhost",
|
"vhost",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"virtio-queue",
|
"virtio-queue",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vm-virtio",
|
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1235,7 +1197,7 @@ dependencies = [
|
|||||||
"option_parser",
|
"option_parser",
|
||||||
"qcow",
|
"qcow",
|
||||||
"vhost",
|
"vhost",
|
||||||
"vhost_user_backend",
|
"vhost-user-backend",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1253,7 +1215,7 @@ dependencies = [
|
|||||||
"net_util",
|
"net_util",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"vhost",
|
"vhost",
|
||||||
"vhost_user_backend",
|
"vhost-user-backend",
|
||||||
"virtio-bindings",
|
"virtio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -1302,6 +1264,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-queue"
|
name = "virtio-queue"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rust-vmm/vm-virtio?branch=main#bbb22d43558a76cc7cc9c262c4be870a9e682a86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -1334,13 +1297,13 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-fdt"
|
name = "vm-fdt"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#9cfa0c8d7c3032f79589c7b01c8722a37f4cf44f"
|
source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#ca35d96191f8232bd7ab8c3e72ec925bf04bd2e0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1382,10 +1345,11 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
"block_util",
|
"block_util",
|
||||||
"clap",
|
"clap",
|
||||||
"credibility",
|
|
||||||
"devices",
|
"devices",
|
||||||
"epoll",
|
"epoll",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
|
"gdbstub",
|
||||||
|
"gdbstub_arch",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
37
Cargo.toml
37
Cargo.toml
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "20.0.0"
|
version = "22.0.0"
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
default-run = "cloud-hypervisor"
|
default-run = "cloud-hypervisor"
|
||||||
@@ -8,60 +8,61 @@ build = "build.rs"
|
|||||||
license = "LICENSE-APACHE & LICENSE-BSD-3-Clause"
|
license = "LICENSE-APACHE & LICENSE-BSD-3-Clause"
|
||||||
description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM"
|
description = "Open source Virtual Machine Monitor (VMM) that runs on top of KVM"
|
||||||
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
homepage = "https://github.com/cloud-hypervisor/cloud-hypervisor"
|
||||||
|
# Minimum buildable version:
|
||||||
|
# Keep in sync with version in .github/workflows/build.yaml
|
||||||
|
rust-version = "1.54"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
api_client = { path = "api_client" }
|
api_client = { path = "api_client" }
|
||||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
clap = { version = "3.1.5", features = ["wrap_help","cargo"] }
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
event_monitor = { path = "event_monitor" }
|
event_monitor = { path = "event_monitor" }
|
||||||
hypervisor = { path = "hypervisor" }
|
hypervisor = { path = "hypervisor" }
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = { version = "0.4.14", features = ["std"] }
|
log = { version = "0.4.14", features = ["std"] }
|
||||||
option_parser = { path = "option_parser" }
|
option_parser = { path = "option_parser" }
|
||||||
seccompiler = "0.2.0"
|
seccompiler = "0.2.0"
|
||||||
serde_json = "1.0.72"
|
serde_json = "1.0.79"
|
||||||
signal-hook = "0.3.10"
|
signal-hook = "0.3.13"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
vmm = { path = "vmm" }
|
vmm = { path = "vmm" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-memory = "0.6.0"
|
vm-memory = "0.7.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
clap = { version = "2.34.0", features = ["wrap_help"] }
|
clap = { version = "3.1.5", features = ["wrap_help"] }
|
||||||
|
|
||||||
# List of patched crates
|
# List of patched crates
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
|
||||||
|
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||||
|
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
credibility = "0.1.3"
|
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
lazy_static= "1.4.0"
|
lazy_static= "1.4.0"
|
||||||
net_util = { path = "net_util" }
|
net_util = { path = "net_util" }
|
||||||
serde_json = "1.0.72"
|
serde_json = "1.0.79"
|
||||||
test_infra = { path = "test_infra" }
|
test_infra = { path = "test_infra" }
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["common", "kvm"]
|
default = ["common", "kvm"]
|
||||||
# Common features for all hypervisors
|
# Common features for all hypervisors
|
||||||
common = ["acpi", "cmos", "fwdebug", "io_uring"]
|
common = ["acpi", "cmos", "fwdebug"]
|
||||||
acpi = ["vmm/acpi"]
|
acpi = ["vmm/acpi"]
|
||||||
cmos = ["vmm/cmos"]
|
cmos = ["vmm/cmos"]
|
||||||
fwdebug = ["vmm/fwdebug"]
|
fwdebug = ["vmm/fwdebug"]
|
||||||
|
gdb = ["vmm/gdb"]
|
||||||
kvm = ["vmm/kvm"]
|
kvm = ["vmm/kvm"]
|
||||||
mshv = ["vmm/mshv"]
|
mshv = ["vmm/mshv"]
|
||||||
io_uring = ["vmm/io_uring"]
|
|
||||||
tdx = ["vmm/tdx"]
|
tdx = ["vmm/tdx"]
|
||||||
|
|
||||||
# Integration tests require a special environment to run in
|
|
||||||
integration_tests = []
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"acpi_tables",
|
"acpi_tables",
|
||||||
@@ -75,19 +76,17 @@ members = [
|
|||||||
"net_util",
|
"net_util",
|
||||||
"option_parser",
|
"option_parser",
|
||||||
"pci",
|
"pci",
|
||||||
|
"performance-metrics",
|
||||||
"qcow",
|
"qcow",
|
||||||
"rate_limiter",
|
"rate_limiter",
|
||||||
"vfio_user",
|
"vfio_user",
|
||||||
"vhdx",
|
"vhdx",
|
||||||
"vhost_user_backend",
|
|
||||||
"vhost_user_block",
|
"vhost_user_block",
|
||||||
"vhost_user_net",
|
"vhost_user_net",
|
||||||
"virtio-devices",
|
"virtio-devices",
|
||||||
"virtio-queue",
|
|
||||||
"vmm",
|
"vmm",
|
||||||
"vm-allocator",
|
"vm-allocator",
|
||||||
"vm-device",
|
"vm-device",
|
||||||
"vm-migration",
|
"vm-migration",
|
||||||
"vm-virtio"
|
"vm-virtio"
|
||||||
]
|
]
|
||||||
exclude = ["test_infra"]
|
|
||||||
|
|||||||
130
Jenkinsfile
vendored
130
Jenkinsfile
vendored
@@ -1,9 +1,28 @@
|
|||||||
|
def runWorkers = true
|
||||||
pipeline{
|
pipeline{
|
||||||
agent none
|
agent none
|
||||||
stages {
|
stages {
|
||||||
stage ('Early checks') {
|
stage ('Early checks') {
|
||||||
agent { node { label 'built-in' } }
|
agent { node { label 'built-in' } }
|
||||||
stages {
|
stages {
|
||||||
|
stage ('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Check for documentation only changes') {
|
||||||
|
when {
|
||||||
|
expression {
|
||||||
|
return docsFileOnly()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
runWorkers = false
|
||||||
|
echo "Documentation only changes, no need to run the CI"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stage ('Check for RFC/WIP builds') {
|
stage ('Check for RFC/WIP builds') {
|
||||||
when {
|
when {
|
||||||
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
changeRequest comparator: 'REGEXP', title: '.*(rfc|RFC|wip|WIP).*'
|
||||||
@@ -22,15 +41,22 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Build') {
|
stage ('Build') {
|
||||||
parallel {
|
parallel {
|
||||||
stage ('Worker build') {
|
stage ('Worker build') {
|
||||||
agent { node { label 'hirsute' } }
|
agent { node { label 'hirsute' } }
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
checkout scm
|
checkout scm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage ('Run OpenAPI tests') {
|
stage ('Run OpenAPI tests') {
|
||||||
steps {
|
steps {
|
||||||
sh "scripts/run_openapi_tests.sh"
|
sh "scripts/run_openapi_tests.sh"
|
||||||
@@ -54,6 +80,12 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('AArch64 worker build') {
|
stage ('AArch64 worker build') {
|
||||||
agent { node { label 'bionic-arm64' } }
|
agent { node { label 'bionic-arm64' } }
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -62,7 +94,7 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Run unit tests') {
|
stage ('Run unit tests') {
|
||||||
steps {
|
steps {
|
||||||
sh "scripts/dev_cli.sh tests --unit"
|
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage ('Run integration tests') {
|
stage ('Run integration tests') {
|
||||||
@@ -71,7 +103,7 @@ pipeline{
|
|||||||
}
|
}
|
||||||
steps {
|
steps {
|
||||||
sh "sudo modprobe openvswitch"
|
sh "sudo modprobe openvswitch"
|
||||||
sh "scripts/dev_cli.sh tests --integration"
|
sh "scripts/dev_cli.sh tests --integration --libc musl"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -84,12 +116,19 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Worker build (musl)') {
|
stage ('Worker build (musl)') {
|
||||||
agent { node { label 'hirsute' } }
|
agent { node { label 'hirsute' } }
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
checkout scm
|
checkout scm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage ('Run unit tests for musl') {
|
stage ('Run unit tests for musl') {
|
||||||
steps {
|
steps {
|
||||||
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
sh "scripts/dev_cli.sh tests --unit --libc musl"
|
||||||
@@ -110,7 +149,12 @@ pipeline{
|
|||||||
agent { node { label 'bionic-sgx' } }
|
agent { node { label 'bionic-sgx' } }
|
||||||
when {
|
when {
|
||||||
beforeAgent true
|
beforeAgent true
|
||||||
branch 'main'
|
allOf {
|
||||||
|
branch 'main'
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
@@ -146,7 +190,12 @@ pipeline{
|
|||||||
agent { node { label 'bionic-vfio' } }
|
agent { node { label 'bionic-vfio' } }
|
||||||
when {
|
when {
|
||||||
beforeAgent true
|
beforeAgent true
|
||||||
branch 'main'
|
allOf {
|
||||||
|
branch 'main'
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
@@ -180,6 +229,12 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Worker build - Windows guest') {
|
stage ('Worker build - Windows guest') {
|
||||||
agent { node { label 'hirsute' } }
|
agent { node { label 'hirsute' } }
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
environment {
|
environment {
|
||||||
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
AZURE_CONNECTION_STRING = credentials('46b4e7d6-315f-4cc1-8333-b58780863b9b')
|
||||||
}
|
}
|
||||||
@@ -189,11 +244,14 @@ pipeline{
|
|||||||
checkout scm
|
checkout scm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage ('Install azure-cli') {
|
||||||
|
steps {
|
||||||
|
installAzureCli()
|
||||||
|
}
|
||||||
|
}
|
||||||
stage ('Download assets') {
|
stage ('Download assets') {
|
||||||
steps {
|
steps {
|
||||||
sh "sudo apt install -y azure-cli"
|
|
||||||
sh "mkdir ${env.HOME}/workloads"
|
sh "mkdir ${env.HOME}/workloads"
|
||||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/OVMF-4b47d0c6c8.fd" --name OVMF-4b47d0c6c8.fd --connection-string "$AZURE_CONNECTION_STRING"'
|
|
||||||
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
sh 'az storage blob download --container-name private-images --file "$HOME/workloads/windows-server-2019.raw" --name windows-server-2019.raw --connection-string "$AZURE_CONNECTION_STRING"'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,6 +275,12 @@ pipeline{
|
|||||||
}
|
}
|
||||||
stage ('Worker build - Live Migration') {
|
stage ('Worker build - Live Migration') {
|
||||||
agent { node { label 'hirsute-small' } }
|
agent { node { label 'hirsute-small' } }
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
stages {
|
stages {
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
steps {
|
steps {
|
||||||
@@ -243,6 +307,39 @@ pipeline{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stage ('Worker build - Metrics') {
|
||||||
|
agent { node { label 'focal-metrics' } }
|
||||||
|
when {
|
||||||
|
branch 'main'
|
||||||
|
beforeAgent true
|
||||||
|
expression {
|
||||||
|
return runWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
environment {
|
||||||
|
METRICS_PUBLISH_KEY = credentials('52e0945f-ce7a-43d1-87af-67d1d87cc40f')
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage ('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Run metrics tests') {
|
||||||
|
options {
|
||||||
|
timeout(time: 1, unit: 'HOURS')
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
sh 'scripts/dev_cli.sh tests --metrics -- -- --report-file /root/workloads/metrics.json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage ('Upload metrics report') {
|
||||||
|
steps {
|
||||||
|
sh 'curl -X PUT https://cloud-hypervisor-metrics.azurewebsites.net/api/publishmetrics -H "x-functions-key: $METRICS_PUBLISH_KEY" -T ~/workloads/metrics.json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -278,3 +375,22 @@ def cancelPreviousBuilds() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def installAzureCli() {
|
||||||
|
sh "sudo apt install -y ca-certificates curl apt-transport-https lsb-release gnupg"
|
||||||
|
sh "curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null"
|
||||||
|
sh "echo \"deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ hirsute main\" | sudo tee /etc/apt/sources.list.d/azure-cli.list"
|
||||||
|
sh "sudo apt update"
|
||||||
|
sh "sudo apt install -y azure-cli"
|
||||||
|
}
|
||||||
|
|
||||||
|
def boolean docsFileOnly() {
|
||||||
|
if (env.CHANGE_TARGET == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sh(
|
||||||
|
returnStatus: true,
|
||||||
|
script: "git diff --name-only origin/${env.CHANGE_TARGET}... | grep -v '\\.md'"
|
||||||
|
) != 0
|
||||||
|
}
|
||||||
|
|||||||
165
README.md
165
README.md
@@ -4,6 +4,7 @@
|
|||||||
- [Architectures](#architectures)
|
- [Architectures](#architectures)
|
||||||
- [Guest OS](#guest-os)
|
- [Guest OS](#guest-os)
|
||||||
- [2. Getting Started](#2-getting-started)
|
- [2. Getting Started](#2-getting-started)
|
||||||
|
- [Preparation](#preparation)
|
||||||
- [Install prerequisites](#install-prerequisites)
|
- [Install prerequisites](#install-prerequisites)
|
||||||
- [Clone and build](#clone-and-build)
|
- [Clone and build](#clone-and-build)
|
||||||
- [Containerized builds and tests](#containerized-builds-and-tests)
|
- [Containerized builds and tests](#containerized-builds-and-tests)
|
||||||
@@ -26,12 +27,19 @@
|
|||||||
|
|
||||||
# 1. What is Cloud Hypervisor?
|
# 1. What is Cloud Hypervisor?
|
||||||
|
|
||||||
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt) and the MSHV hypervisors .
|
Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on
|
||||||
|
top of [KVM](https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt)
|
||||||
|
hypervisor and Microsoft Hypervisor (MSHV).
|
||||||
|
|
||||||
The project focuses on exclusively running modern, cloud workloads, on top of a limited set of hardware architectures and platforms.
|
The project focuses on exclusively running modern, cloud workloads, on top of
|
||||||
Cloud workloads refers to those that are usually run by customers inside a cloud provider. For our purposes this means modern operating systems with most I/O handled by paravirtualised devices (i.e. virtio), no requirement for legacy devices, and 64-bit CPUs.
|
a limited set of hardware architectures and platforms. Cloud workloads refers
|
||||||
|
to those that are usually run by customers inside a cloud provider. For our
|
||||||
|
purposes this means modern operating systems with most I/O handled by
|
||||||
|
paravirtualised devices (i.e. virtio), no requirement for legacy devices, and
|
||||||
|
64-bit CPUs.
|
||||||
|
|
||||||
Cloud Hypervisor is implemented in [Rust](https://www.rust-lang.org/) and is based on the [rust-vmm](https://github.com/rust-vmm) crates.
|
Cloud Hypervisor is implemented in [Rust](https://www.rust-lang.org/) and is
|
||||||
|
based on the [rust-vmm](https://github.com/rust-vmm) crates.
|
||||||
|
|
||||||
## Objectives
|
## Objectives
|
||||||
|
|
||||||
@@ -50,7 +58,9 @@ Cloud Hypervisor is implemented in [Rust](https://www.rust-lang.org/) and is bas
|
|||||||
|
|
||||||
### Architectures
|
### Architectures
|
||||||
|
|
||||||
Cloud Hypervisor supports the `x86-64` and `AArch64` architectures. There are some small differences in functionality between the two architectures (see [#1125](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/1125)).
|
Cloud Hypervisor supports the `x86-64` and `AArch64` architectures. There are
|
||||||
|
some small differences in functionality between the two architectures
|
||||||
|
(see [#1125](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/1125)).
|
||||||
|
|
||||||
### Guest OS
|
### Guest OS
|
||||||
|
|
||||||
@@ -73,9 +83,9 @@ $ mkdir $CLOUDH
|
|||||||
|
|
||||||
## Install prerequisites
|
## Install prerequisites
|
||||||
|
|
||||||
You need to install some prerequisite packages in order to build and test Cloud Hypervisor.
|
You need to install some prerequisite packages in order to build and test Cloud
|
||||||
Here, all the steps are based on Ubuntu, for other Linux distributions please replace the
|
Hypervisor. Here, all the steps are based on Ubuntu, for other Linux
|
||||||
package manager and package name.
|
distributions please replace the package manager and package name.
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Install git
|
# Install git
|
||||||
@@ -106,7 +116,8 @@ $ cargo build --release --target=x86_64-unknown-linux-musl --all
|
|||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
This will build a `cloud-hypervisor` binary under `$CLOUDH/cloud-hypervisor/target/release/cloud-hypervisor`.
|
This will build a `cloud-hypervisor` binary under
|
||||||
|
`$CLOUDH/cloud-hypervisor/target/release/cloud-hypervisor`.
|
||||||
|
|
||||||
### Containerized builds and tests
|
### Containerized builds and tests
|
||||||
|
|
||||||
@@ -138,18 +149,20 @@ development script commands and their related options.
|
|||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
You can run a guest VM by either using an existing cloud image or booting into your own kernel and disk image.
|
You can run a guest VM by either using an existing cloud image or booting into
|
||||||
|
your own kernel and disk image.
|
||||||
|
|
||||||
### Cloud image
|
### Cloud image
|
||||||
|
|
||||||
Cloud Hypervisor supports booting disk images containing all needed
|
Cloud Hypervisor supports booting disk images containing all needed
|
||||||
components to run cloud workloads, a.k.a. cloud images. To do that we rely on
|
components to run cloud workloads, a.k.a. cloud images. To do that we rely on
|
||||||
the [Rust Hypervisor
|
the [Rust Hypervisor
|
||||||
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) project to provide
|
Firmware](https://github.com/cloud-hypervisor/rust-hypervisor-firmware) project
|
||||||
an ELF
|
to provide an ELF formatted KVM firmware for `cloud-hypervisor` to directly
|
||||||
formatted KVM firmware for `cloud-hypervisor` to directly boot into.
|
boot into.
|
||||||
|
|
||||||
We need to get the latest `rust-hypervisor-firmware` release and also a working cloud image. Here we will use a Ubuntu image:
|
We need to get the latest `rust-hypervisor-firmware` release and also a working
|
||||||
|
cloud image. Here we will use a Ubuntu image:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
@@ -167,8 +180,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
|||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
--disk path=focal-server-cloudimg-amd64.raw \
|
||||||
--cpus boot=4 \
|
--cpus boot=4 \
|
||||||
--memory size=1024M \
|
--memory size=1024M \
|
||||||
--net "tap=,mac=,ip=,mask=" \
|
--net "tap=,mac=,ip=,mask="
|
||||||
--rng
|
|
||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -178,7 +190,10 @@ Multiple arguments can be given to the `--disk` parameter.
|
|||||||
|
|
||||||
#### Building your kernel
|
#### Building your kernel
|
||||||
|
|
||||||
Cloud Hypervisor also supports direct kernel boot into a `vmlinux` ELF kernel. In order to support virtio-iommu we have our own development branch. You are of course able to use your own kernel but these instructions will continue with the version that we develop and test against.
|
Cloud Hypervisor also supports direct kernel boot into a `vmlinux` ELF kernel.
|
||||||
|
In order to support virtio-watchdog we have our own development branch. You are
|
||||||
|
of course able to use your own kernel but these instructions will continue with
|
||||||
|
the version that we develop and test against.
|
||||||
|
|
||||||
To build the kernel:
|
To build the kernel:
|
||||||
|
|
||||||
@@ -186,20 +201,22 @@ To build the kernel:
|
|||||||
|
|
||||||
# Clone the Cloud Hypervisor Linux branch
|
# Clone the Cloud Hypervisor Linux branch
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.14 linux-cloud-hypervisor
|
$ git clone --depth 1 https://github.com/cloud-hypervisor/linux.git -b ch-5.15.12 linux-cloud-hypervisor
|
||||||
$ pushd linux-cloud-hypervisor
|
$ pushd linux-cloud-hypervisor
|
||||||
|
|
||||||
# Use the cloud-hypervisor kernel config to build your kernel
|
# Use the cloud-hypervisor kernel config to build your kernel
|
||||||
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-x86_64 .config
|
$ cp $CLOUDH/cloud-hypervisor/resources/linux-config-x86_64 .config
|
||||||
$ make bzImage -j `nproc`
|
$ KCFLAGS="-Wa,-mx86-used-note=no" make bzImage -j `nproc`
|
||||||
$ popd
|
$ popd
|
||||||
```
|
```
|
||||||
|
|
||||||
The `vmlinux` kernel image will then be located at `linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin`.
|
The `vmlinux` kernel image will then be located at
|
||||||
|
`linux-cloud-hypervisor/arch/x86/boot/compressed/vmlinux.bin`.
|
||||||
|
|
||||||
#### Disk image
|
#### Disk image
|
||||||
|
|
||||||
For the disk image, we will use a Ubuntu cloud image that contains a root partition:
|
For the disk image, we will use a Ubuntu cloud image that contains a root
|
||||||
|
partition:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
@@ -210,8 +227,8 @@ $ popd
|
|||||||
|
|
||||||
#### Booting the guest VM
|
#### Booting the guest VM
|
||||||
|
|
||||||
Now we can directly boot into our custom kernel and make it use the Ubuntu root partition.
|
Now we can directly boot into our custom kernel and make it use the Ubuntu root
|
||||||
If we want to have 4 vCPUs and 1024 MBytes of memory:
|
partition. If we want to have 4 vCPUs and 1024 MBytes of memory:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ pushd $CLOUDH
|
$ pushd $CLOUDH
|
||||||
@@ -222,8 +239,7 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
|||||||
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
--cmdline "console=hvc0 root=/dev/vda1 rw" \
|
||||||
--cpus boot=4 \
|
--cpus boot=4 \
|
||||||
--memory size=1024M \
|
--memory size=1024M \
|
||||||
--net "tap=,mac=,ip=,mask=" \
|
--net "tap=,mac=,ip=,mask="
|
||||||
--rng
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The above example use the `virtio-console` device as the guest console, and this
|
The above example use the `virtio-console` device as the guest console, and this
|
||||||
@@ -242,13 +258,13 @@ $ ./cloud-hypervisor/target/release/cloud-hypervisor \
|
|||||||
--cmdline "console=ttyS0 root=/dev/vda1 rw" \
|
--cmdline "console=ttyS0 root=/dev/vda1 rw" \
|
||||||
--cpus boot=4 \
|
--cpus boot=4 \
|
||||||
--memory size=1024M \
|
--memory size=1024M \
|
||||||
--net "tap=,mac=,ip=,mask=" \
|
--net "tap=,mac=,ip=,mask="
|
||||||
--rng
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# 3. Status
|
# 3. Status
|
||||||
|
|
||||||
Cloud Hypervisor is under active development. The following stability guarantees are currently made:
|
Cloud Hypervisor is under active development. The following stability guarantees
|
||||||
|
are currently made:
|
||||||
|
|
||||||
* The API (including command line options) will not be removed or changed in a
|
* The API (including command line options) will not be removed or changed in a
|
||||||
breaking way without a minimum of 2 releases notice. Where possible warnings
|
breaking way without a minimum of 2 releases notice. Where possible warnings
|
||||||
@@ -272,70 +288,87 @@ As of 2021-04-29, the following cloud images are supported:
|
|||||||
- [Ubuntu Groovy](https://cloud-images.ubuntu.com/groovy/current/) (cloudimg)
|
- [Ubuntu Groovy](https://cloud-images.ubuntu.com/groovy/current/) (cloudimg)
|
||||||
- [Ubuntu Hirsute](https://cloud-images.ubuntu.com/hirsute/current/) (cloudimg)
|
- [Ubuntu Hirsute](https://cloud-images.ubuntu.com/hirsute/current/) (cloudimg)
|
||||||
|
|
||||||
Direct kernel boot to userspace should work with a rootfs from most distributions.
|
Direct kernel boot to userspace should work with a rootfs from most
|
||||||
|
distributions.
|
||||||
|
|
||||||
## Hot Plug
|
## Hot Plug
|
||||||
|
|
||||||
Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO), `virtio-{net,block,pmem,fs,vsock}` and memory resizing. This [document](docs/hotplug.md) details how to add devices to
|
Cloud Hypervisor supports hotplug of CPUs, passthrough devices (VFIO),
|
||||||
a running VM.
|
`virtio-{net,block,pmem,fs,vsock}` and memory resizing. This
|
||||||
|
[document](docs/hotplug.md) details how to add devices to a running VM.
|
||||||
|
|
||||||
## Device Model
|
## Device Model
|
||||||
|
|
||||||
Details of the device model can be found in this [documentation](docs/device_model.md).
|
Details of the device model can be found in this
|
||||||
|
[documentation](docs/device_model.md).
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
We are not tracking the Cloud Hypervisor TODO list from a specific git tracked file but through
|
We are not tracking the Cloud Hypervisor TODO list from a specific git tracked
|
||||||
[github issues](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new) instead.
|
file but through
|
||||||
|
[github issues](https://github.com/cloud-hypervisor/cloud-hypervisor/issues/new)
|
||||||
|
instead.
|
||||||
|
|
||||||
# 4. `rust-vmm` project dependency
|
# 4. `rust-vmm` project dependency
|
||||||
|
|
||||||
In order to satisfy the design goal of having a high-performance, security-focused hypervisor the decision
|
In order to satisfy the design goal of having a high-performance,
|
||||||
was made to use the [Rust](https://www.rust-lang.org/) programming language.
|
security-focused hypervisor the decision was made to use the
|
||||||
The language's strong focus on memory and thread safety makes it an ideal candidate for implementing VMMs.
|
[Rust](https://www.rust-lang.org/) programming language. The language's strong
|
||||||
|
focus on memory and thread safety makes it an ideal candidate for implementing
|
||||||
|
VMMs.
|
||||||
|
|
||||||
Instead of implementing the VMM components from scratch, Cloud Hypervisor is importing the [rust-vmm](https://github.com/rust-vmm)
|
Instead of implementing the VMM components from scratch, Cloud Hypervisor is
|
||||||
crates, and sharing code and architecture together with other VMMs like e.g. Amazon's [Firecracker](https://firecracker-microvm.github.io/)
|
importing the [rust-vmm](https://github.com/rust-vmm) crates, and sharing code
|
||||||
and Google's [crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/).
|
and architecture together with other VMMs like e.g. Amazon's
|
||||||
|
[Firecracker](https://firecracker-microvm.github.io/) and Google's
|
||||||
|
[crosvm](https://chromium.googlesource.com/chromiumos/platform/crosvm/).
|
||||||
|
|
||||||
Cloud Hypervisor embraces the rust-vmm project goals, which is to be able to share and re-use
|
Cloud Hypervisor embraces the rust-vmm project goals, which is to be able to
|
||||||
as many virtualization crates as possible. As such, the Cloud Hypervisor relationship with the rust-vmm
|
share and re-use as many virtualization crates as possible. As such, the Cloud
|
||||||
project is twofold:
|
Hypervisor relationship with the rust-vmm project is twofold:
|
||||||
|
|
||||||
1. It will use as much of the rust-vmm code as possible. Any new rust-vmm crate that's relevant to the project
|
1. It will use as much of the rust-vmm code as possible. Any new rust-vmm crate
|
||||||
goals will be integrated as soon as possible.
|
that's relevant to the project goals will be integrated as soon as possible.
|
||||||
2. As it is likely that the rust-vmm project will lack some of the features that Cloud Hypervisor needs (e.g. ACPI,
|
2. As it is likely that the rust-vmm project will lack some of the features that
|
||||||
VFIO, vhost-user, etc), we will be using the Cloud Hypervisor VMM to implement and test them, and contribute them
|
Cloud Hypervisor needs (e.g. ACPI, VFIO, vhost-user, etc), we will be using
|
||||||
back to the rust-vmm project.
|
the Cloud Hypervisor VMM to implement and test them, and contribute them back
|
||||||
|
to the rust-vmm project.
|
||||||
|
|
||||||
## Firecracker and crosvm
|
## Firecracker and crosvm
|
||||||
|
|
||||||
A large part of the Cloud Hypervisor code is based on either the Firecracker or the crosvm projects implementations.
|
A large part of the Cloud Hypervisor code is based on either the Firecracker or
|
||||||
Both of these are VMMs written in Rust with a focus on safety and security, like Cloud Hypervisor.
|
the crosvm projects implementations. Both of these are VMMs written in Rust with
|
||||||
|
a focus on safety and security, like Cloud Hypervisor.
|
||||||
|
|
||||||
However we want to emphasize that the Cloud Hypervisor project is neither a fork nor a reimplementation of any of those
|
However we want to emphasize that the Cloud Hypervisor project is neither a fork
|
||||||
projects. The goals and use cases we're trying to meet are different.
|
nor a reimplementation of any of those projects. The goals and use cases we're
|
||||||
We're aiming at supporting cloud workloads, i.e. those modern, full Linux distribution images currently being run by
|
trying to meet are different. We're aiming at supporting cloud workloads, i.e.
|
||||||
Cloud Service Provider (CSP) tenants.
|
those modern, full Linux distribution images currently being run by Cloud
|
||||||
|
Service Provider (CSP) tenants.
|
||||||
|
|
||||||
Our primary target is not to support client or serverless use cases, and as such our code base already diverges
|
Our primary target is not to support client or serverless use cases, and as such
|
||||||
from the crosvm and Firecracker ones. As we add more features to support our use cases, we believe that the divergence
|
our code base already diverges from the crosvm and Firecracker ones. As we add
|
||||||
will increase while at the same time sharing as much of the fundamental virtualization code through the rust-vmm project
|
more features to support our use cases, we believe that the divergence will
|
||||||
crates as possible.
|
increase while at the same time sharing as much of the fundamental
|
||||||
|
virtualization code through the rust-vmm project crates as possible.
|
||||||
|
|
||||||
# 5. Community
|
# 5. Community
|
||||||
|
|
||||||
The Cloud Hypervisor project follows the governance, and community guidelines described in
|
The Cloud Hypervisor project follows the governance, and community guidelines
|
||||||
the [Community](https://github.com/cloud-hypervisor/community) repository.
|
described in the [Community](https://github.com/cloud-hypervisor/community)
|
||||||
|
repository.
|
||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
We are working on building a global, diverse and collaborative community around the Cloud Hypervisor project.
|
We are working on building a global, diverse and collaborative community around
|
||||||
Anyone who is interested in [contributing](CONTRIBUTING.md) to the project is welcome to participate.
|
the Cloud Hypervisor project. Anyone who is interested in
|
||||||
|
[contributing](CONTRIBUTING.md) to the project is welcome to participate.
|
||||||
|
|
||||||
We believe that contributing to a open source project like Cloud Hypervisor covers a lot more than just sending
|
We believe that contributing to a open source project like Cloud Hypervisor
|
||||||
code. Testing, documentation, pull request reviews, bug reports, feature requests, project improvement suggestions,
|
covers a lot more than just sending code. Testing, documentation, pull request
|
||||||
etc, are all equal and welcome means of contribution. See the [CONTRIBUTING](CONTRIBUTING.md) document for more details.
|
reviews, bug reports, feature requests, project improvement suggestions, etc,
|
||||||
|
are all equal and welcome means of contribution. See the
|
||||||
|
[CONTRIBUTING](CONTRIBUTING.md) document for more details.
|
||||||
|
|
||||||
## Join us
|
## Join us
|
||||||
|
|
||||||
@@ -344,4 +377,4 @@ and [join us on Slack](https://cloud-hypervisor.slack.com/).
|
|||||||
|
|
||||||
## Security issues
|
## Security issues
|
||||||
|
|
||||||
Please use the GitHub security advisories feature for reporting issues: https://github.com/cloud-hypervisor/cloud-hypervisor/security/advisories/new
|
Please contact the maintainers listed in the MAINTAINERS.md file with security issues.
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
vm-memory = "0.6.0"
|
vm-memory = "0.7.0"
|
||||||
|
|||||||
@@ -1392,13 +1392,13 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pkg_length() {
|
fn test_pkg_length() {
|
||||||
assert_eq!(create_pkg_length(&[0u8; 62].to_vec(), true), vec![63]);
|
assert_eq!(create_pkg_length(&[0u8; 62], true), vec![63]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_pkg_length(&[0u8; 64].to_vec(), true),
|
create_pkg_length(&[0u8; 64], true),
|
||||||
vec![1 << 6 | (66 & 0xf), 66 >> 4]
|
vec![1 << 6 | (66 & 0xf), 66 >> 4]
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
create_pkg_length(&[0u8; 4096].to_vec(), true),
|
create_pkg_length(&[0u8; 4096], true),
|
||||||
vec![
|
vec![
|
||||||
2 << 6 | (4099 & 0xf) as u8,
|
2 << 6 | (4099 & 0xf) as u8,
|
||||||
(4099 >> 4) as u8,
|
(4099 >> 4) as u8,
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ tdx = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
linux-loader = { version = "0.4.0", features = ["elf", "bzimage", "pe"] }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
serde = { version = "1.0.130", features = ["rc"] }
|
serde = { version = "1.0.136", features = ["rc"] }
|
||||||
serde_derive = "1.0.130"
|
serde_derive = "1.0.136"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-bitmap"] }
|
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-bitmap"] }
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
use crate::NumaNodes;
|
use crate::{NumaNodes, PciSpaceInfo};
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -22,7 +22,7 @@ use super::get_fdt_addr;
|
|||||||
use super::gic::GicDevice;
|
use super::gic::GicDevice;
|
||||||
use super::layout::{
|
use super::layout::{
|
||||||
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
|
||||||
PCI_HIGH_BASE, PCI_MMCONFIG_SIZE, PCI_MMCONFIG_START,
|
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||||
};
|
};
|
||||||
use vm_fdt::{FdtWriter, FdtWriterResult};
|
use vm_fdt::{FdtWriter, FdtWriterResult};
|
||||||
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryRegion};
|
||||||
@@ -51,11 +51,16 @@ const SIZE_CELLS: u32 = 0x2;
|
|||||||
// Look for "The 1st cell..."
|
// Look for "The 1st cell..."
|
||||||
const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
|
const GIC_FDT_IRQ_TYPE_SPI: u32 = 0;
|
||||||
const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
|
const GIC_FDT_IRQ_TYPE_PPI: u32 = 1;
|
||||||
|
const GIC_FDT_IRQ_PPI_CPU_SHIFT: u32 = 8;
|
||||||
|
const GIC_FDT_IRQ_PPI_CPU_MASK: u32 = 0xff << GIC_FDT_IRQ_PPI_CPU_SHIFT;
|
||||||
|
|
||||||
// From https://elixir.bootlin.com/linux/v4.9.62/source/include/dt-bindings/interrupt-controller/irq.h#L17
|
// From https://elixir.bootlin.com/linux/v4.9.62/source/include/dt-bindings/interrupt-controller/irq.h#L17
|
||||||
const IRQ_TYPE_EDGE_RISING: u32 = 1;
|
const IRQ_TYPE_EDGE_RISING: u32 = 1;
|
||||||
const IRQ_TYPE_LEVEL_HI: u32 = 4;
|
const IRQ_TYPE_LEVEL_HI: u32 = 4;
|
||||||
|
|
||||||
|
// PMU PPI interrupt number
|
||||||
|
pub const AARCH64_PMU_IRQ: u32 = 7;
|
||||||
|
|
||||||
// Keys and Buttons
|
// Keys and Buttons
|
||||||
// System Power Down
|
// System Power Down
|
||||||
const KEY_POWER: u32 = 116;
|
const KEY_POWER: u32 = 116;
|
||||||
@@ -88,9 +93,10 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
|||||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &dyn GicDevice,
|
||||||
initrd: &Option<InitramfsConfig>,
|
initrd: &Option<InitramfsConfig>,
|
||||||
pci_space_address: &(u64, u64),
|
pci_space_info: &[PciSpaceInfo],
|
||||||
numa_nodes: &NumaNodes,
|
numa_nodes: &NumaNodes,
|
||||||
virtio_iommu_bdf: Option<u32>,
|
virtio_iommu_bdf: Option<u32>,
|
||||||
|
pmu_supported: bool,
|
||||||
) -> FdtWriterResult<Vec<u8>> {
|
) -> FdtWriterResult<Vec<u8>> {
|
||||||
// Allocate stuff necessary for the holding the blob.
|
// Allocate stuff necessary for the holding the blob.
|
||||||
let mut fdt = FdtWriter::new().unwrap();
|
let mut fdt = FdtWriter::new().unwrap();
|
||||||
@@ -114,15 +120,13 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
|
|||||||
create_chosen_node(&mut fdt, cmdline, initrd)?;
|
create_chosen_node(&mut fdt, cmdline, initrd)?;
|
||||||
create_gic_node(&mut fdt, gic_device)?;
|
create_gic_node(&mut fdt, gic_device)?;
|
||||||
create_timer_node(&mut fdt)?;
|
create_timer_node(&mut fdt)?;
|
||||||
|
if pmu_supported {
|
||||||
|
create_pmu_node(&mut fdt, vcpu_mpidr.len())?;
|
||||||
|
}
|
||||||
create_clock_node(&mut fdt)?;
|
create_clock_node(&mut fdt)?;
|
||||||
create_psci_node(&mut fdt)?;
|
create_psci_node(&mut fdt)?;
|
||||||
create_devices_node(&mut fdt, device_info)?;
|
create_devices_node(&mut fdt, device_info)?;
|
||||||
create_pci_nodes(
|
create_pci_nodes(&mut fdt, pci_space_info, virtio_iommu_bdf)?;
|
||||||
&mut fdt,
|
|
||||||
pci_space_address.0,
|
|
||||||
pci_space_address.1,
|
|
||||||
virtio_iommu_bdf,
|
|
||||||
)?;
|
|
||||||
if numa_nodes.len() > 1 {
|
if numa_nodes.len() > 1 {
|
||||||
create_distance_map_node(&mut fdt, numa_nodes)?;
|
create_distance_map_node(&mut fdt, numa_nodes)?;
|
||||||
}
|
}
|
||||||
@@ -157,9 +161,6 @@ fn create_cpu_nodes(
|
|||||||
fdt.property_u32("#size-cells", 0x0)?;
|
fdt.property_u32("#size-cells", 0x0)?;
|
||||||
|
|
||||||
let num_cpus = vcpu_mpidr.len();
|
let num_cpus = vcpu_mpidr.len();
|
||||||
let threads_per_core = vcpu_topology.unwrap_or_default().0 as u8;
|
|
||||||
let cores_per_package = vcpu_topology.unwrap_or_default().1 as u8;
|
|
||||||
let packages = vcpu_topology.unwrap_or_default().2 as u8;
|
|
||||||
|
|
||||||
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
|
||||||
let cpu_name = format!("cpu@{:x}", cpu_id);
|
let cpu_name = format!("cpu@{:x}", cpu_id);
|
||||||
@@ -188,32 +189,9 @@ fn create_cpu_nodes(
|
|||||||
fdt.end_node(cpu_node)?;
|
fdt.end_node(cpu_node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a valid cpu topology config, create the cpu-map node.
|
if let Some(topology) = vcpu_topology {
|
||||||
if (threads_per_core > 0)
|
let (threads_per_core, cores_per_package, packages) = topology;
|
||||||
&& (cores_per_package > 0)
|
|
||||||
&& (packages > 0)
|
|
||||||
&& (num_cpus as u8 == threads_per_core * cores_per_package * packages)
|
|
||||||
{
|
|
||||||
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
let cpu_map_node = fdt.begin_node("cpu-map")?;
|
||||||
// Create mappings between CPU index and cluster,core, and thread.
|
|
||||||
let mut cluster_core_thread_to_cpuidx = HashMap::new();
|
|
||||||
for cpu_idx in 0..num_cpus as u8 {
|
|
||||||
if threads_per_core > 1 {
|
|
||||||
cluster_core_thread_to_cpuidx.insert(
|
|
||||||
(
|
|
||||||
cpu_idx / (cores_per_package * threads_per_core),
|
|
||||||
(cpu_idx / threads_per_core) % cores_per_package,
|
|
||||||
cpu_idx % threads_per_core,
|
|
||||||
),
|
|
||||||
cpu_idx,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
cluster_core_thread_to_cpuidx.insert(
|
|
||||||
(cpu_idx / cores_per_package, cpu_idx % cores_per_package, 0),
|
|
||||||
cpu_idx,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create device tree nodes with regard of above mapping.
|
// Create device tree nodes with regard of above mapping.
|
||||||
for cluster_idx in 0..packages {
|
for cluster_idx in 0..packages {
|
||||||
@@ -224,24 +202,16 @@ fn create_cpu_nodes(
|
|||||||
let core_name = format!("core{:x}", core_idx);
|
let core_name = format!("core{:x}", core_idx);
|
||||||
let core_node = fdt.begin_node(&core_name)?;
|
let core_node = fdt.begin_node(&core_name)?;
|
||||||
|
|
||||||
if threads_per_core > 1 {
|
for thread_idx in 0..threads_per_core {
|
||||||
for thread_idx in 0..threads_per_core {
|
let thread_name = format!("thread{:x}", thread_idx);
|
||||||
let thread_name = format!("thread{:x}", thread_idx);
|
let thread_node = fdt.begin_node(&thread_name)?;
|
||||||
let thread_node = fdt.begin_node(&thread_name)?;
|
let cpu_idx = threads_per_core * cores_per_package * cluster_idx
|
||||||
let cpu_idx = cluster_core_thread_to_cpuidx
|
+ threads_per_core * core_idx
|
||||||
.get(&(cluster_idx, core_idx, thread_idx))
|
+ thread_idx;
|
||||||
.unwrap();
|
fdt.property_u32("cpu", cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
||||||
|
fdt.end_node(thread_node)?;
|
||||||
fdt.property_u32("cpu", *cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
|
||||||
fdt.end_node(thread_node)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let cpu_idx = cluster_core_thread_to_cpuidx
|
|
||||||
.get(&(cluster_idx, core_idx, 0))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
fdt.property_u32("cpu", *cpu_idx as u32 + FIRST_VCPU_PHANDLE)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fdt.end_node(core_node)?;
|
fdt.end_node(core_node)?;
|
||||||
}
|
}
|
||||||
fdt.end_node(cluster_node)?;
|
fdt.end_node(cluster_node)?;
|
||||||
@@ -545,110 +515,165 @@ fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Buil
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_pmu_node(fdt: &mut FdtWriter, cpu_nums: usize) -> FdtWriterResult<()> {
|
||||||
|
let num_cpus = cpu_nums as u64 as u32;
|
||||||
|
let compatible = "arm,armv8-pmuv3";
|
||||||
|
let cpu_mask: u32 =
|
||||||
|
(((1 << num_cpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT) & GIC_FDT_IRQ_PPI_CPU_MASK;
|
||||||
|
let irq = [
|
||||||
|
GIC_FDT_IRQ_TYPE_PPI,
|
||||||
|
AARCH64_PMU_IRQ,
|
||||||
|
cpu_mask | IRQ_TYPE_LEVEL_HI,
|
||||||
|
];
|
||||||
|
|
||||||
|
let pmu_node = fdt.begin_node("pmu")?;
|
||||||
|
fdt.property_string("compatible", compatible)?;
|
||||||
|
fdt.property_array_u32("interrupts", &irq)?;
|
||||||
|
fdt.end_node(pmu_node)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn create_pci_nodes(
|
fn create_pci_nodes(
|
||||||
fdt: &mut FdtWriter,
|
fdt: &mut FdtWriter,
|
||||||
pci_device_base: u64,
|
pci_device_info: &[PciSpaceInfo],
|
||||||
pci_device_size: u64,
|
|
||||||
virtio_iommu_bdf: Option<u32>,
|
virtio_iommu_bdf: Option<u32>,
|
||||||
) -> FdtWriterResult<()> {
|
) -> FdtWriterResult<()> {
|
||||||
// Add node for PCIe controller.
|
// Add node for PCIe controller.
|
||||||
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
|
// See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel
|
||||||
// and https://elinux.org/Device_Tree_Usage.
|
// and https://elinux.org/Device_Tree_Usage.
|
||||||
|
// In multiple PCI segments setup, each PCI segment needs a PCI node.
|
||||||
|
for pci_device_info_elem in pci_device_info.iter() {
|
||||||
|
// EDK2 requires the PCIe high space above 4G address.
|
||||||
|
// The actual space in CLH follows the RAM. If the RAM space is small, the PCIe high space
|
||||||
|
// could fall bellow 4G.
|
||||||
|
// Here we cut off PCI device space below 8G in FDT to workaround the EDK2 check.
|
||||||
|
// But the address written in ACPI is not impacted.
|
||||||
|
let (pci_device_base_64bit, pci_device_size_64bit) = if cfg!(feature = "acpi")
|
||||||
|
&& (pci_device_info_elem.pci_device_space_start < PCI_HIGH_BASE)
|
||||||
|
{
|
||||||
|
(
|
||||||
|
PCI_HIGH_BASE,
|
||||||
|
pci_device_info_elem.pci_device_space_size
|
||||||
|
- (PCI_HIGH_BASE - pci_device_info_elem.pci_device_space_start),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
pci_device_info_elem.pci_device_space_start,
|
||||||
|
pci_device_info_elem.pci_device_space_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// There is no specific requirement of the 32bit MMIO range, and
|
||||||
|
// therefore at least we can make these ranges 4K aligned.
|
||||||
|
let pci_device_size_32bit: u64 =
|
||||||
|
MEM_32BIT_DEVICES_SIZE / ((1 << 12) * pci_device_info.len() as u64) * (1 << 12);
|
||||||
|
let pci_device_base_32bit: u64 = MEM_32BIT_DEVICES_START.0
|
||||||
|
+ pci_device_size_32bit * pci_device_info_elem.pci_segment_id as u64;
|
||||||
|
|
||||||
// EDK2 requires the PCIe high space above 4G address.
|
let ranges = [
|
||||||
// The actual space in CLH follows the RAM. If the RAM space is small, the PCIe high space
|
// io addresses. Since AArch64 will not use IO address,
|
||||||
// could fall bellow 4G.
|
// we can set the same IO address range for every segment.
|
||||||
// Here we put it above 512G in FDT to workaround the EDK2 check.
|
0x1000000,
|
||||||
// But the address written in ACPI is not impacted.
|
|
||||||
let pci_device_base_64bit: u64 = if cfg!(feature = "acpi") {
|
|
||||||
pci_device_base + PCI_HIGH_BASE
|
|
||||||
} else {
|
|
||||||
pci_device_base
|
|
||||||
};
|
|
||||||
let pci_device_size_64bit: u64 = if cfg!(feature = "acpi") {
|
|
||||||
pci_device_size - PCI_HIGH_BASE
|
|
||||||
} else {
|
|
||||||
pci_device_size
|
|
||||||
};
|
|
||||||
|
|
||||||
let ranges = [
|
|
||||||
// io addresses
|
|
||||||
0x1000000,
|
|
||||||
0_u32,
|
|
||||||
0_u32,
|
|
||||||
(MEM_PCI_IO_START.0 >> 32) as u32,
|
|
||||||
MEM_PCI_IO_START.0 as u32,
|
|
||||||
(MEM_PCI_IO_SIZE >> 32) as u32,
|
|
||||||
MEM_PCI_IO_SIZE as u32,
|
|
||||||
// mmio addresses
|
|
||||||
0x2000000, // (ss = 10: 32-bit memory space)
|
|
||||||
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // PCI address
|
|
||||||
MEM_32BIT_DEVICES_START.0 as u32,
|
|
||||||
(MEM_32BIT_DEVICES_START.0 >> 32) as u32, // CPU address
|
|
||||||
MEM_32BIT_DEVICES_START.0 as u32,
|
|
||||||
(MEM_32BIT_DEVICES_SIZE >> 32) as u32, // size
|
|
||||||
MEM_32BIT_DEVICES_SIZE as u32,
|
|
||||||
// device addresses
|
|
||||||
0x3000000, // (ss = 11: 64-bit memory space)
|
|
||||||
(pci_device_base_64bit >> 32) as u32, // PCI address
|
|
||||||
pci_device_base_64bit as u32,
|
|
||||||
(pci_device_base_64bit >> 32) as u32, // CPU address
|
|
||||||
pci_device_base_64bit as u32,
|
|
||||||
(pci_device_size_64bit >> 32) as u32, // size
|
|
||||||
pci_device_size_64bit as u32,
|
|
||||||
];
|
|
||||||
let bus_range = [0, 0]; // Only bus 0
|
|
||||||
let reg = [PCI_MMCONFIG_START.0, PCI_MMCONFIG_SIZE];
|
|
||||||
|
|
||||||
let pci_node = fdt.begin_node("pci")?;
|
|
||||||
fdt.property_string("compatible", "pci-host-ecam-generic")?;
|
|
||||||
fdt.property_string("device_type", "pci")?;
|
|
||||||
fdt.property_array_u32("ranges", &ranges)?;
|
|
||||||
fdt.property_array_u32("bus-range", &bus_range)?;
|
|
||||||
fdt.property_u32("#address-cells", 3)?;
|
|
||||||
fdt.property_u32("#size-cells", 2)?;
|
|
||||||
fdt.property_array_u64("reg", ®)?;
|
|
||||||
fdt.property_u32("#interrupt-cells", 1)?;
|
|
||||||
fdt.property_null("interrupt-map")?;
|
|
||||||
fdt.property_null("interrupt-map-mask")?;
|
|
||||||
fdt.property_null("dma-coherent")?;
|
|
||||||
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
|
|
||||||
|
|
||||||
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
|
|
||||||
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
|
|
||||||
// for 'iommu-map' attribute setting.
|
|
||||||
let iommu_map = [
|
|
||||||
0_u32,
|
0_u32,
|
||||||
VIRTIO_IOMMU_PHANDLE,
|
|
||||||
0_u32,
|
0_u32,
|
||||||
virtio_iommu_bdf,
|
(MEM_PCI_IO_START.0 >> 32) as u32,
|
||||||
virtio_iommu_bdf + 1,
|
MEM_PCI_IO_START.0 as u32,
|
||||||
VIRTIO_IOMMU_PHANDLE,
|
(MEM_PCI_IO_SIZE >> 32) as u32,
|
||||||
virtio_iommu_bdf + 1,
|
MEM_PCI_IO_SIZE as u32,
|
||||||
0xffff - virtio_iommu_bdf,
|
// mmio addresses
|
||||||
|
0x2000000, // (ss = 10: 32-bit memory space)
|
||||||
|
(pci_device_base_32bit >> 32) as u32, // PCI address
|
||||||
|
pci_device_base_32bit as u32,
|
||||||
|
(pci_device_base_32bit >> 32) as u32, // CPU address
|
||||||
|
pci_device_base_32bit as u32,
|
||||||
|
(pci_device_size_32bit >> 32) as u32, // size
|
||||||
|
pci_device_size_32bit as u32,
|
||||||
|
// device addresses
|
||||||
|
0x3000000, // (ss = 11: 64-bit memory space)
|
||||||
|
(pci_device_base_64bit >> 32) as u32, // PCI address
|
||||||
|
pci_device_base_64bit as u32,
|
||||||
|
(pci_device_base_64bit >> 32) as u32, // CPU address
|
||||||
|
pci_device_base_64bit as u32,
|
||||||
|
(pci_device_size_64bit >> 32) as u32, // size
|
||||||
|
pci_device_size_64bit as u32,
|
||||||
|
];
|
||||||
|
let bus_range = [0, 0]; // Only bus 0
|
||||||
|
let reg = [
|
||||||
|
pci_device_info_elem.mmio_config_address,
|
||||||
|
PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
|
||||||
|
];
|
||||||
|
// See kernel document Documentation/devicetree/bindings/pci/pci-msi.txt
|
||||||
|
let msi_map = [
|
||||||
|
// rid-base: A single cell describing the first RID matched by the entry.
|
||||||
|
0x0,
|
||||||
|
// msi-controller: A single phandle to an MSI controller.
|
||||||
|
MSI_PHANDLE,
|
||||||
|
// msi-base: An msi-specifier describing the msi-specifier produced for the
|
||||||
|
// first RID matched by the entry.
|
||||||
|
(pci_device_info_elem.pci_segment_id as u32) << 8,
|
||||||
|
// length: A single cell describing how many consecutive RIDs are matched
|
||||||
|
// following the rid-base.
|
||||||
|
0x100,
|
||||||
];
|
];
|
||||||
fdt.property_array_u32("iommu-map", &iommu_map)?;
|
|
||||||
|
|
||||||
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
let pci_node_name = format!("pci@{:x}", pci_device_info_elem.mmio_config_address);
|
||||||
// for virtio-iommu node settings.
|
let pci_node = fdt.begin_node(&pci_node_name)?;
|
||||||
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
|
||||||
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
|
||||||
fdt.property_u32("#iommu-cells", 1)?;
|
|
||||||
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
|
||||||
|
|
||||||
// 'reg' is a five-cell address encoded as
|
fdt.property_string("compatible", "pci-host-ecam-generic")?;
|
||||||
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
|
fdt.property_string("device_type", "pci")?;
|
||||||
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
|
fdt.property_array_u32("ranges", &ranges)?;
|
||||||
// should be zero.
|
fdt.property_array_u32("bus-range", &bus_range)?;
|
||||||
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
|
fdt.property_u32(
|
||||||
fdt.property_array_u32("reg", ®)?;
|
"linux,pci-domain",
|
||||||
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
|
pci_device_info_elem.pci_segment_id as u32,
|
||||||
|
)?;
|
||||||
|
fdt.property_u32("#address-cells", 3)?;
|
||||||
|
fdt.property_u32("#size-cells", 2)?;
|
||||||
|
fdt.property_array_u64("reg", ®)?;
|
||||||
|
fdt.property_u32("#interrupt-cells", 1)?;
|
||||||
|
fdt.property_null("interrupt-map")?;
|
||||||
|
fdt.property_null("interrupt-map-mask")?;
|
||||||
|
fdt.property_null("dma-coherent")?;
|
||||||
|
fdt.property_array_u32("msi-map", &msi_map)?;
|
||||||
|
fdt.property_u32("msi-parent", MSI_PHANDLE)?;
|
||||||
|
|
||||||
fdt.end_node(virtio_iommu_node)?;
|
if pci_device_info_elem.pci_segment_id == 0 {
|
||||||
|
if let Some(virtio_iommu_bdf) = virtio_iommu_bdf {
|
||||||
|
// See kernel document Documentation/devicetree/bindings/pci/pci-iommu.txt
|
||||||
|
// for 'iommu-map' attribute setting.
|
||||||
|
let iommu_map = [
|
||||||
|
0_u32,
|
||||||
|
VIRTIO_IOMMU_PHANDLE,
|
||||||
|
0_u32,
|
||||||
|
virtio_iommu_bdf,
|
||||||
|
virtio_iommu_bdf + 1,
|
||||||
|
VIRTIO_IOMMU_PHANDLE,
|
||||||
|
virtio_iommu_bdf + 1,
|
||||||
|
0xffff - virtio_iommu_bdf,
|
||||||
|
];
|
||||||
|
fdt.property_array_u32("iommu-map", &iommu_map)?;
|
||||||
|
|
||||||
|
// See kernel document Documentation/devicetree/bindings/virtio/iommu.txt
|
||||||
|
// for virtio-iommu node settings.
|
||||||
|
let virtio_iommu_node_name = format!("virtio_iommu@{:x}", virtio_iommu_bdf);
|
||||||
|
let virtio_iommu_node = fdt.begin_node(&virtio_iommu_node_name)?;
|
||||||
|
fdt.property_u32("#iommu-cells", 1)?;
|
||||||
|
fdt.property_string("compatible", "virtio,pci-iommu")?;
|
||||||
|
|
||||||
|
// 'reg' is a five-cell address encoded as
|
||||||
|
// (phys.hi phys.mid phys.lo size.hi size.lo). phys.hi should contain the
|
||||||
|
// device's BDF as 0b00000000 bbbbbbbb dddddfff 00000000. The other cells
|
||||||
|
// should be zero.
|
||||||
|
let reg = [virtio_iommu_bdf << 8, 0_u32, 0_u32, 0_u32, 0_u32];
|
||||||
|
fdt.property_array_u32("reg", ®)?;
|
||||||
|
fdt.property_u32("phandle", VIRTIO_IOMMU_PHANDLE)?;
|
||||||
|
|
||||||
|
fdt.end_node(virtio_iommu_node)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fdt.end_node(pci_node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fdt.end_node(pci_node)?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ macro_rules! VGIC_DIST_REG {
|
|||||||
|
|
||||||
// List with relevant distributor registers that we will be restoring.
|
// List with relevant distributor registers that we will be restoring.
|
||||||
// Order is taken from qemu.
|
// Order is taken from qemu.
|
||||||
static VGIC_DIST_REGS: &'static [DistReg] = &[
|
static VGIC_DIST_REGS: &[DistReg] = &[
|
||||||
VGIC_DIST_REG!(GICD_STATUSR, 0, 4),
|
VGIC_DIST_REG!(GICD_STATUSR, 0, 4),
|
||||||
VGIC_DIST_REG!(GICD_ICENABLER, 1, 0),
|
VGIC_DIST_REG!(GICD_ICENABLER, 1, 0),
|
||||||
VGIC_DIST_REG!(GICD_ISENABLER, 1, 0),
|
VGIC_DIST_REG!(GICD_ISENABLER, 1, 0),
|
||||||
|
|||||||
@@ -124,12 +124,11 @@ pub mod kvm {
|
|||||||
its_device: &Arc<dyn hypervisor::Device>,
|
its_device: &Arc<dyn hypervisor::Device>,
|
||||||
save: bool,
|
save: bool,
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
let attr: u64;
|
let attr = if save {
|
||||||
if save {
|
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES)
|
||||||
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES);
|
|
||||||
} else {
|
} else {
|
||||||
attr = u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES);
|
u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES)
|
||||||
}
|
};
|
||||||
|
|
||||||
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
||||||
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R1_EL1, 1);
|
|||||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R2_EL1, 2);
|
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R2_EL1, 2);
|
||||||
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R3_EL1, 3);
|
SYS_ICC_AP1Rn_EL1!(SYS_ICC_AP1R3_EL1, 3);
|
||||||
|
|
||||||
static VGIC_ICC_REGS: &'static [u64] = &[
|
static VGIC_ICC_REGS: &[u64] = &[
|
||||||
SYS_ICC_SRE_EL1,
|
SYS_ICC_SRE_EL1,
|
||||||
SYS_ICC_CTLR_EL1,
|
SYS_ICC_CTLR_EL1,
|
||||||
SYS_ICC_IGRPEN0_EL1,
|
SYS_ICC_IGRPEN0_EL1,
|
||||||
@@ -91,8 +91,7 @@ fn icc_attr_access(
|
|||||||
flags: 0,
|
flags: 0,
|
||||||
};
|
};
|
||||||
if set {
|
if set {
|
||||||
#[allow(clippy::unnecessary_mut_passed)]
|
gic.set_device_attr(&gic_icc_attr)
|
||||||
gic.set_device_attr(&mut gic_icc_attr)
|
|
||||||
.map_err(Error::SetDeviceAttribute)?;
|
.map_err(Error::SetDeviceAttribute)?;
|
||||||
} else {
|
} else {
|
||||||
gic.get_device_attr(&mut gic_icc_attr)
|
gic.get_device_attr(&mut gic_icc_attr)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ macro_rules! VGIC_RDIST_REG {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// List with relevant distributor registers that we will be restoring.
|
// List with relevant distributor registers that we will be restoring.
|
||||||
static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
static VGIC_RDIST_REGS: &[RdistReg] = &[
|
||||||
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
VGIC_RDIST_REG!(GICR_STATUSR, 4),
|
||||||
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
VGIC_RDIST_REG!(GICR_WAKER, 4),
|
||||||
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
VGIC_RDIST_REG!(GICR_PROPBASER, 8),
|
||||||
@@ -70,7 +70,7 @@ static VGIC_RDIST_REGS: &'static [RdistReg] = &[
|
|||||||
];
|
];
|
||||||
|
|
||||||
// List with relevant distributor registers that we will be restoring.
|
// List with relevant distributor registers that we will be restoring.
|
||||||
static VGIC_SGI_REGS: &'static [RdistReg] = &[
|
static VGIC_SGI_REGS: &[RdistReg] = &[
|
||||||
VGIC_RDIST_REG!(GICR_IGROUPR0, 4),
|
VGIC_RDIST_REG!(GICR_IGROUPR0, 4),
|
||||||
VGIC_RDIST_REG!(GICR_ICENABLER0, 4),
|
VGIC_RDIST_REG!(GICR_ICENABLER0, 4),
|
||||||
VGIC_RDIST_REG!(GICR_ISENABLER0, 4),
|
VGIC_RDIST_REG!(GICR_ISENABLER0, 4),
|
||||||
@@ -96,8 +96,7 @@ fn redist_attr_access(
|
|||||||
flags: 0,
|
flags: 0,
|
||||||
};
|
};
|
||||||
if set {
|
if set {
|
||||||
#[allow(clippy::unnecessary_mut_passed)]
|
gic.set_device_attr(&gic_dist_attr)
|
||||||
gic.set_device_attr(&mut gic_dist_attr)
|
|
||||||
.map_err(Error::SetDeviceAttribute)?;
|
.map_err(Error::SetDeviceAttribute)?;
|
||||||
} else {
|
} else {
|
||||||
gic.get_device_attr(&mut gic_dist_attr)
|
gic.get_device_attr(&mut gic_dist_attr)
|
||||||
@@ -110,7 +109,7 @@ fn access_redists_aux(
|
|||||||
gic: &Arc<dyn hypervisor::Device>,
|
gic: &Arc<dyn hypervisor::Device>,
|
||||||
gicr_typer: &[u64],
|
gicr_typer: &[u64],
|
||||||
state: &mut Vec<u32>,
|
state: &mut Vec<u32>,
|
||||||
reg_list: &'static [RdistReg],
|
reg_list: &[RdistReg],
|
||||||
idx: &mut usize,
|
idx: &mut usize,
|
||||||
set: bool,
|
set: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
|||||||
@@ -82,6 +82,8 @@ pub const MEM_32BIT_DEVICES_SIZE: u64 = 0x2000_0000;
|
|||||||
/// PCI MMCONFIG space (start: after the device space at 1 GiB, length: 256MiB)
|
/// PCI MMCONFIG space (start: after the device space at 1 GiB, length: 256MiB)
|
||||||
pub const PCI_MMCONFIG_START: GuestAddress = GuestAddress(0x3000_0000);
|
pub const PCI_MMCONFIG_START: GuestAddress = GuestAddress(0x3000_0000);
|
||||||
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
||||||
|
// One bus with potentially 256 devices (32 slots x 8 functions).
|
||||||
|
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
|
||||||
|
|
||||||
/// Start of RAM on 64 bit ARM.
|
/// Start of RAM on 64 bit ARM.
|
||||||
pub const RAM_64BIT_START: u64 = 0x4000_0000;
|
pub const RAM_64BIT_START: u64 = 0x4000_0000;
|
||||||
@@ -104,7 +106,7 @@ pub const RSDP_POINTER: GuestAddress = GuestAddress(ACPI_START);
|
|||||||
pub const KERNEL_START: u64 = ACPI_START + ACPI_MAX_SIZE as u64;
|
pub const KERNEL_START: u64 = ACPI_START + ACPI_MAX_SIZE as u64;
|
||||||
|
|
||||||
/// Pci high memory base
|
/// Pci high memory base
|
||||||
pub const PCI_HIGH_BASE: u64 = 0x80_0000_0000_u64;
|
pub const PCI_HIGH_BASE: u64 = 0x2_0000_0000_u64;
|
||||||
|
|
||||||
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
|
// As per virt/kvm/arm/vgic/vgic-kvm-device.c we need
|
||||||
// the number of interrupts our GIC will support to be:
|
// the number of interrupts our GIC will support to be:
|
||||||
|
|||||||
@@ -14,16 +14,14 @@ pub mod regs;
|
|||||||
pub mod uefi;
|
pub mod uefi;
|
||||||
|
|
||||||
pub use self::fdt::DeviceInfoForFdt;
|
pub use self::fdt::DeviceInfoForFdt;
|
||||||
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, RegionType};
|
use crate::{DeviceType, GuestMemoryMmap, NumaNodes, PciSpaceInfo, RegionType};
|
||||||
use gic::GicDevice;
|
use gic::GicDevice;
|
||||||
use log::{log_enabled, Level};
|
use log::{log_enabled, Level};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vm_memory::{
|
use vm_memory::{Address, GuestAddress, GuestMemory, GuestUsize};
|
||||||
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryAtomic, GuestUsize,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Errors thrown while configuring aarch64 system.
|
/// Errors thrown while configuring aarch64 system.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -45,6 +43,9 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Error configuring the MPIDR register
|
/// Error configuring the MPIDR register
|
||||||
VcpuRegMpidr(hypervisor::HypervisorCpuError),
|
VcpuRegMpidr(hypervisor::HypervisorCpuError),
|
||||||
|
|
||||||
|
/// Error initializing PMU for vcpu
|
||||||
|
VcpuInitPmu,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for super::Error {
|
impl From<Error> for super::Error {
|
||||||
@@ -66,16 +67,10 @@ pub fn configure_vcpu(
|
|||||||
fd: &Arc<dyn hypervisor::Vcpu>,
|
fd: &Arc<dyn hypervisor::Vcpu>,
|
||||||
id: u8,
|
id: u8,
|
||||||
kernel_entry_point: Option<EntryPoint>,
|
kernel_entry_point: Option<EntryPoint>,
|
||||||
vm_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
|
||||||
) -> super::Result<u64> {
|
) -> super::Result<u64> {
|
||||||
if let Some(kernel_entry_point) = kernel_entry_point {
|
if let Some(kernel_entry_point) = kernel_entry_point {
|
||||||
regs::setup_regs(
|
regs::setup_regs(fd, id, kernel_entry_point.entry_addr.raw_value())
|
||||||
fd,
|
.map_err(Error::RegsConfiguration)?;
|
||||||
id,
|
|
||||||
kernel_entry_point.entry_addr.raw_value(),
|
|
||||||
&vm_memory.memory(),
|
|
||||||
)
|
|
||||||
.map_err(Error::RegsConfiguration)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mpidr = fd.read_mpidr().map_err(Error::VcpuRegMpidr)?;
|
let mpidr = fd.read_mpidr().map_err(Error::VcpuRegMpidr)?;
|
||||||
@@ -140,10 +135,11 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
|||||||
vcpu_topology: Option<(u8, u8, u8)>,
|
vcpu_topology: Option<(u8, u8, u8)>,
|
||||||
device_info: &HashMap<(DeviceType, String), T, S>,
|
device_info: &HashMap<(DeviceType, String), T, S>,
|
||||||
initrd: &Option<super::InitramfsConfig>,
|
initrd: &Option<super::InitramfsConfig>,
|
||||||
pci_space_address: &(u64, u64),
|
pci_space_info: &[PciSpaceInfo],
|
||||||
virtio_iommu_bdf: Option<u32>,
|
virtio_iommu_bdf: Option<u32>,
|
||||||
gic_device: &dyn GicDevice,
|
gic_device: &dyn GicDevice,
|
||||||
numa_nodes: &NumaNodes,
|
numa_nodes: &NumaNodes,
|
||||||
|
pmu_supported: bool,
|
||||||
) -> super::Result<()> {
|
) -> super::Result<()> {
|
||||||
let fdt_final = fdt::create_fdt(
|
let fdt_final = fdt::create_fdt(
|
||||||
guest_mem,
|
guest_mem,
|
||||||
@@ -153,9 +149,10 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
|
|||||||
device_info,
|
device_info,
|
||||||
gic_device,
|
gic_device,
|
||||||
initrd,
|
initrd,
|
||||||
pci_space_address,
|
pci_space_info,
|
||||||
numa_nodes,
|
numa_nodes,
|
||||||
virtio_iommu_bdf,
|
virtio_iommu_bdf,
|
||||||
|
pmu_supported,
|
||||||
)
|
)
|
||||||
.map_err(|_| Error::SetupFdt)?;
|
.map_err(|_| Error::SetupFdt)?;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
use super::get_fdt_addr;
|
use super::get_fdt_addr;
|
||||||
use crate::GuestMemoryMmap;
|
|
||||||
use hypervisor::kvm::kvm_bindings::{
|
use hypervisor::kvm::kvm_bindings::{
|
||||||
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
kvm_regs, user_pt_regs, KVM_REG_ARM64, KVM_REG_ARM_CORE, KVM_REG_SIZE_U64,
|
||||||
};
|
};
|
||||||
@@ -43,12 +42,7 @@ const PSTATE_FAULT_BITS_64: u64 = PSR_MODE_EL1h | PSR_A_BIT | PSR_F_BIT | PSR_I_
|
|||||||
/// * `cpu_id` - Index of current vcpu.
|
/// * `cpu_id` - Index of current vcpu.
|
||||||
/// * `boot_ip` - Starting instruction pointer.
|
/// * `boot_ip` - Starting instruction pointer.
|
||||||
/// * `mem` - Reserved DRAM for current VM.
|
/// * `mem` - Reserved DRAM for current VM.
|
||||||
pub fn setup_regs(
|
pub fn setup_regs(vcpu: &Arc<dyn hypervisor::Vcpu>, cpu_id: u8, boot_ip: u64) -> Result<()> {
|
||||||
vcpu: &Arc<dyn hypervisor::Vcpu>,
|
|
||||||
cpu_id: u8,
|
|
||||||
boot_ip: u64,
|
|
||||||
_mem: &GuestMemoryMmap,
|
|
||||||
) -> Result<()> {
|
|
||||||
let kreg_off = offset__of!(kvm_regs, regs);
|
let kreg_off = offset__of!(kvm_regs, regs);
|
||||||
|
|
||||||
// Get the register index of the PSTATE (Processor State) register.
|
// Get the register index of the PSTATE (Processor State) register.
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
//! Implements platform specific functionality.
|
//! Implements platform specific functionality.
|
||||||
//! Supported platforms: x86_64, aarch64.
|
//! Supported platforms: x86_64, aarch64.
|
||||||
#![allow(clippy::transmute_ptr_to_ptr, clippy::redundant_static_lifetimes)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
@@ -162,6 +161,16 @@ pub struct MmioDeviceInfo {
|
|||||||
pub irq: u32,
|
pub irq: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structure to describe PCI space information
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
pub struct PciSpaceInfo {
|
||||||
|
pub pci_segment_id: u16,
|
||||||
|
pub mmio_config_address: u64,
|
||||||
|
pub pci_device_space_start: u64,
|
||||||
|
pub pci_device_space_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
impl DeviceInfoForFdt for MmioDeviceInfo {
|
impl DeviceInfoForFdt for MmioDeviceInfo {
|
||||||
fn addr(&self) -> u64 {
|
fn addr(&self) -> u64 {
|
||||||
|
|||||||
@@ -93,6 +93,16 @@ pub const MEM_32BIT_DEVICES_SIZE: u64 = 640 << 20;
|
|||||||
pub const PCI_MMCONFIG_START: GuestAddress =
|
pub const PCI_MMCONFIG_START: GuestAddress =
|
||||||
GuestAddress(MEM_32BIT_DEVICES_START.0 + MEM_32BIT_DEVICES_SIZE);
|
GuestAddress(MEM_32BIT_DEVICES_START.0 + MEM_32BIT_DEVICES_SIZE);
|
||||||
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
pub const PCI_MMCONFIG_SIZE: u64 = 256 << 20;
|
||||||
|
// One bus with potentially 256 devices (32 slots x 8 functions).
|
||||||
|
pub const PCI_MMIO_CONFIG_SIZE_PER_SEGMENT: u64 = 4096 * 256;
|
||||||
|
|
||||||
|
// TSS is 3 pages after the PCI MMCONFIG space
|
||||||
|
pub const KVM_TSS_START: GuestAddress = GuestAddress(PCI_MMCONFIG_START.0 + PCI_MMCONFIG_SIZE);
|
||||||
|
pub const KVM_TSS_SIZE: u64 = (3 * 4) << 10;
|
||||||
|
|
||||||
|
// Identity map is a one page region after the TSS
|
||||||
|
pub const KVM_IDENTITY_MAP_START: GuestAddress = GuestAddress(KVM_TSS_START.0 + KVM_TSS_SIZE);
|
||||||
|
pub const KVM_IDENTITY_MAP_SIZE: u64 = 4 << 10;
|
||||||
|
|
||||||
// IOAPIC
|
// IOAPIC
|
||||||
pub const IOAPIC_START: GuestAddress = GuestAddress(0xfec0_0000);
|
pub const IOAPIC_START: GuestAddress = GuestAddress(0xfec0_0000);
|
||||||
@@ -101,9 +111,6 @@ pub const IOAPIC_SIZE: u64 = 0x20;
|
|||||||
// APIC
|
// APIC
|
||||||
pub const APIC_START: GuestAddress = GuestAddress(0xfee0_0000);
|
pub const APIC_START: GuestAddress = GuestAddress(0xfee0_0000);
|
||||||
|
|
||||||
/// Address for the TSS setup.
|
|
||||||
pub const KVM_TSS_ADDRESS: GuestAddress = GuestAddress(0xfffb_d000);
|
|
||||||
|
|
||||||
// == End of "32-bit reserved" range. ==
|
// == End of "32-bit reserved" range. ==
|
||||||
|
|
||||||
// ** 64-bit RAM start (start: 4GiB, length: varies) **
|
// ** 64-bit RAM start (start: 4GiB, length: varies) **
|
||||||
|
|||||||
@@ -315,21 +315,12 @@ impl CpuidPatch {
|
|||||||
|
|
||||||
for entry in entries.iter() {
|
for entry in entries.iter() {
|
||||||
if entry.function == function && entry.index == index {
|
if entry.function == function && entry.index == index {
|
||||||
let reg_val: u32;
|
let reg_val = match reg {
|
||||||
match reg {
|
CpuidReg::EAX => entry.eax,
|
||||||
CpuidReg::EAX => {
|
CpuidReg::EBX => entry.ebx,
|
||||||
reg_val = entry.eax;
|
CpuidReg::ECX => entry.ecx,
|
||||||
}
|
CpuidReg::EDX => entry.edx,
|
||||||
CpuidReg::EBX => {
|
};
|
||||||
reg_val = entry.ebx;
|
|
||||||
}
|
|
||||||
CpuidReg::ECX => {
|
|
||||||
reg_val = entry.ecx;
|
|
||||||
}
|
|
||||||
CpuidReg::EDX => {
|
|
||||||
reg_val = entry.edx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (reg_val & mask) == mask;
|
return (reg_val & mask) == mask;
|
||||||
}
|
}
|
||||||
@@ -522,19 +513,14 @@ impl CpuidFeatureEntry {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let entry = &feature_entry_list[i];
|
let entry = &feature_entry_list[i];
|
||||||
let entry_compatible;
|
let entry_compatible = match entry.compatible_check {
|
||||||
match entry.compatible_check {
|
|
||||||
CpuidCompatibleCheck::BitwiseSubset => {
|
CpuidCompatibleCheck::BitwiseSubset => {
|
||||||
let different_feature_bits = src_vm_feature ^ dest_vm_feature;
|
let different_feature_bits = src_vm_feature ^ dest_vm_feature;
|
||||||
let src_vm_feature_bits_only = different_feature_bits & src_vm_feature;
|
let src_vm_feature_bits_only = different_feature_bits & src_vm_feature;
|
||||||
entry_compatible = src_vm_feature_bits_only == 0;
|
src_vm_feature_bits_only == 0
|
||||||
}
|
|
||||||
CpuidCompatibleCheck::Equal => {
|
|
||||||
entry_compatible = src_vm_feature == dest_vm_feature;
|
|
||||||
}
|
|
||||||
CpuidCompatibleCheck::NumNotGreater => {
|
|
||||||
entry_compatible = src_vm_feature <= dest_vm_feature;
|
|
||||||
}
|
}
|
||||||
|
CpuidCompatibleCheck::Equal => src_vm_feature == dest_vm_feature,
|
||||||
|
CpuidCompatibleCheck::NumNotGreater => src_vm_feature <= dest_vm_feature,
|
||||||
};
|
};
|
||||||
if !entry_compatible {
|
if !entry_compatible {
|
||||||
error!(
|
error!(
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ pub enum TdvfSectionType {
|
|||||||
Cfv,
|
Cfv,
|
||||||
TdHob,
|
TdHob,
|
||||||
TempMem,
|
TempMem,
|
||||||
|
PermMem,
|
||||||
|
Payload,
|
||||||
|
PayloadParam,
|
||||||
Reserved = 0xffffffff,
|
Reserved = 0xffffffff,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,57 +64,6 @@ impl Default for TdvfSectionType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
#[derive(Clone, Copy, Default, Debug)]
|
|
||||||
pub struct TdVmmDataRegion {
|
|
||||||
pub start_address: u64,
|
|
||||||
pub length: u64,
|
|
||||||
pub region_type: TdVmmDataRegionType,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(u16)]
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum TdVmmDataRegionType {
|
|
||||||
Signature = 0x0000,
|
|
||||||
InterfaceVersion = 0x0001,
|
|
||||||
SystemUuid = 0x0002,
|
|
||||||
RamSize = 0x0003,
|
|
||||||
GraphicsEnabled = 0x0004,
|
|
||||||
SmpCpuCount = 0x0005,
|
|
||||||
MachineId = 0x0006,
|
|
||||||
KernelAddress = 0x0007,
|
|
||||||
KernelSize = 0x0008,
|
|
||||||
KernelCommandLine = 0x0009,
|
|
||||||
InitrdAddress = 0x000a,
|
|
||||||
InitrdSize = 0x000b,
|
|
||||||
BootDevice = 0x000c,
|
|
||||||
NumaData = 0x000d,
|
|
||||||
BootMenu = 0x000e,
|
|
||||||
MaximumCpuCount = 0x000f,
|
|
||||||
KernelEntry = 0x0010,
|
|
||||||
KernelData = 0x0011,
|
|
||||||
InitrdData = 0x0012,
|
|
||||||
CommandLineAddress = 0x0013,
|
|
||||||
CommandLineSize = 0x0014,
|
|
||||||
CommandLineData = 0x0015,
|
|
||||||
KernelSetupAddress = 0x0016,
|
|
||||||
KernelSetupSize = 0x0017,
|
|
||||||
KernelSetupData = 0x0018,
|
|
||||||
FileDir = 0x0019,
|
|
||||||
AcpiTables = 0x8000,
|
|
||||||
SmbiosTables = 0x8001,
|
|
||||||
Irq0Override = 0x8002,
|
|
||||||
E820Table = 0x8003,
|
|
||||||
HpetData = 0x8004,
|
|
||||||
Reserved = 0xffff,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for TdVmmDataRegionType {
|
|
||||||
fn default() -> Self {
|
|
||||||
TdVmmDataRegionType::Reserved
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
pub fn parse_tdvf_sections(file: &mut File) -> Result<Vec<TdvfSection>, TdvfError> {
|
||||||
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
// The 32-bit offset to the TDVF metadata is located 32 bytes from
|
||||||
// the end of the file.
|
// the end of the file.
|
||||||
@@ -231,20 +183,41 @@ struct HobGuidType {
|
|||||||
name: EfiGuid,
|
name: EfiGuid,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(u32)]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum PayloadImageType {
|
||||||
|
ExecutablePayload,
|
||||||
|
BzImage,
|
||||||
|
RawVmLinux,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for PayloadImageType {
|
||||||
|
fn default() -> Self {
|
||||||
|
PayloadImageType::ExecutablePayload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Default, Debug)]
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
struct TdVmmData {
|
pub struct PayloadInfo {
|
||||||
|
pub image_type: PayloadImageType,
|
||||||
|
pub entry_point: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Default, Debug)]
|
||||||
|
struct TdPayload {
|
||||||
guid_type: HobGuidType,
|
guid_type: HobGuidType,
|
||||||
region: TdVmmDataRegion,
|
payload_info: PayloadInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: These data structures only contain a series of integers
|
// SAFETY: These data structures only contain a series of integers
|
||||||
unsafe impl ByteValued for TdVmmDataRegion {}
|
|
||||||
unsafe impl ByteValued for HobHeader {}
|
unsafe impl ByteValued for HobHeader {}
|
||||||
unsafe impl ByteValued for HobHandoffInfoTable {}
|
unsafe impl ByteValued for HobHandoffInfoTable {}
|
||||||
unsafe impl ByteValued for HobResourceDescriptor {}
|
unsafe impl ByteValued for HobResourceDescriptor {}
|
||||||
unsafe impl ByteValued for HobGuidType {}
|
unsafe impl ByteValued for HobGuidType {}
|
||||||
unsafe impl ByteValued for TdVmmData {}
|
unsafe impl ByteValued for PayloadInfo {}
|
||||||
|
unsafe impl ByteValued for TdPayload {}
|
||||||
|
|
||||||
pub struct TdHob {
|
pub struct TdHob {
|
||||||
start_offset: u64,
|
start_offset: u64,
|
||||||
@@ -376,35 +349,90 @@ impl TdHob {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_td_vmm_data(
|
pub fn add_acpi_table(
|
||||||
&mut self,
|
&mut self,
|
||||||
mem: &GuestMemoryMmap,
|
mem: &GuestMemoryMmap,
|
||||||
region: TdVmmDataRegion,
|
table_content: &[u8],
|
||||||
) -> Result<(), TdvfError> {
|
) -> Result<(), TdvfError> {
|
||||||
let td_vmm_data = TdVmmData {
|
// We already know the HobGuidType size is 8 bytes multiple, but we
|
||||||
|
// need the total size to be 8 bytes multiple. That is why the ACPI
|
||||||
|
// table size must be 8 bytes multiple as well.
|
||||||
|
let length = std::mem::size_of::<HobGuidType>() as u16
|
||||||
|
+ align_hob(table_content.len() as u64) as u16;
|
||||||
|
let hob_guid_type = HobGuidType {
|
||||||
|
header: HobHeader {
|
||||||
|
r#type: HobType::GuidExtension,
|
||||||
|
length,
|
||||||
|
reserved: 0,
|
||||||
|
},
|
||||||
|
// ACPI_TABLE_HOB_GUID
|
||||||
|
// 0x6a0c5870, 0xd4ed, 0x44f4, {0xa1, 0x35, 0xdd, 0x23, 0x8b, 0x6f, 0xc, 0x8d }
|
||||||
|
name: EfiGuid {
|
||||||
|
data1: 0x6a0c_5870,
|
||||||
|
data2: 0xd4ed,
|
||||||
|
data3: 0x44f4,
|
||||||
|
data4: [0xa1, 0x35, 0xdd, 0x23, 0x8b, 0x6f, 0xc, 0x8d],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
info!(
|
||||||
|
"Writing HOB ACPI table {:x} {:x?} {:x?}",
|
||||||
|
self.current_offset, hob_guid_type, table_content
|
||||||
|
);
|
||||||
|
mem.write_obj(hob_guid_type, GuestAddress(self.current_offset))
|
||||||
|
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
||||||
|
let current_offset = self.current_offset + std::mem::size_of::<HobGuidType>() as u64;
|
||||||
|
|
||||||
|
// In case the table is quite large, let's make sure we can handle
|
||||||
|
// retrying until everything has been correctly copied.
|
||||||
|
let mut offset: usize = 0;
|
||||||
|
loop {
|
||||||
|
let bytes_written = mem
|
||||||
|
.write(
|
||||||
|
&table_content[offset..],
|
||||||
|
GuestAddress(current_offset + offset as u64),
|
||||||
|
)
|
||||||
|
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
||||||
|
offset += bytes_written;
|
||||||
|
if offset >= table_content.len() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.current_offset += length as u64;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_payload(
|
||||||
|
&mut self,
|
||||||
|
mem: &GuestMemoryMmap,
|
||||||
|
payload_info: PayloadInfo,
|
||||||
|
) -> Result<(), TdvfError> {
|
||||||
|
let payload = TdPayload {
|
||||||
guid_type: HobGuidType {
|
guid_type: HobGuidType {
|
||||||
header: HobHeader {
|
header: HobHeader {
|
||||||
r#type: HobType::GuidExtension,
|
r#type: HobType::GuidExtension,
|
||||||
length: std::mem::size_of::<TdVmmData>() as u16,
|
length: std::mem::size_of::<TdPayload>() as u16,
|
||||||
reserved: 0,
|
reserved: 0,
|
||||||
},
|
},
|
||||||
// TD_VMM_DATA_GUID CF2643E4-C0D3-46FF-0000-72EE623DDE38
|
// HOB_PAYLOAD_INFO_GUID
|
||||||
|
// 0xb96fa412, 0x461f, 0x4be3, {0x8c, 0xd, 0xad, 0x80, 0x5a, 0x49, 0x7a, 0xc0
|
||||||
name: EfiGuid {
|
name: EfiGuid {
|
||||||
data1: 0xcf26_43e4,
|
data1: 0xb96f_a412,
|
||||||
data2: 0xc0d3,
|
data2: 0x461f,
|
||||||
data3: 0x46ff,
|
data3: 0x4be3,
|
||||||
data4: [0x00, 0x00, 0x72, 0xee, 0x62, 0x3d, 0xde, 0x38],
|
data4: [0x8c, 0xd, 0xad, 0x80, 0x5a, 0x49, 0x7a, 0xc0],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
region,
|
payload_info,
|
||||||
};
|
};
|
||||||
info!(
|
info!(
|
||||||
"Writing HOB TD_VMM_DATA {:x} {:x?}",
|
"Writing HOB TD_PAYLOAD {:x} {:x?}",
|
||||||
self.current_offset, td_vmm_data
|
self.current_offset, payload
|
||||||
);
|
);
|
||||||
mem.write_obj(td_vmm_data, GuestAddress(self.current_offset))
|
mem.write_obj(payload, GuestAddress(self.current_offset))
|
||||||
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
.map_err(TdvfError::GuestMemoryWriteHob)?;
|
||||||
self.update_offset::<TdVmmData>();
|
self.update_offset::<TdPayload>();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ edition = "2018"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
io_uring = []
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
io-uring = "0.5.2"
|
io-uring = "0.5.2"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
@@ -18,8 +17,8 @@ versionize = "0.1.6"
|
|||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vhdx = { path = "../vhdx" }
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
virtio-bindings = { version = "0.1.0", features = ["virtio-v5_0_0"] }
|
||||||
virtio-queue = { path = "../virtio-queue" }
|
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
|
use libc::{ioctl, S_IFBLK, S_IFMT};
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
use vmm_sys_util::{ioctl_expr, ioctl_io_nr, ioctl_ioc_nr};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum DiskFileError {
|
pub enum DiskFileError {
|
||||||
@@ -15,11 +20,96 @@ pub enum DiskFileError {
|
|||||||
NewAsyncIo(#[source] std::io::Error),
|
NewAsyncIo(#[source] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DiskTopology {
|
||||||
|
pub logical_block_size: u64,
|
||||||
|
pub physical_block_size: u64,
|
||||||
|
pub minimum_io_size: u64,
|
||||||
|
pub optimal_io_size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DiskTopology {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
logical_block_size: 512,
|
||||||
|
physical_block_size: 512,
|
||||||
|
minimum_io_size: 512,
|
||||||
|
optimal_io_size: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ioctl_io_nr!(BLKSSZGET, 0x12, 104);
|
||||||
|
ioctl_io_nr!(BLKPBSZGET, 0x12, 123);
|
||||||
|
ioctl_io_nr!(BLKIOMIN, 0x12, 120);
|
||||||
|
ioctl_io_nr!(BLKIOOPT, 0x12, 121);
|
||||||
|
|
||||||
|
enum BlockSize {
|
||||||
|
LogicalBlock,
|
||||||
|
PhysicalBlock,
|
||||||
|
MinimumIo,
|
||||||
|
OptimalIo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DiskTopology {
|
||||||
|
fn is_block_device(f: &mut File) -> std::io::Result<bool> {
|
||||||
|
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
|
||||||
|
let ret = unsafe { libc::fstat(f.as_raw_fd(), stat.as_mut_ptr()) };
|
||||||
|
if ret != 0 {
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_block = unsafe { (*stat.as_ptr()).st_mode & S_IFMT == S_IFBLK };
|
||||||
|
Ok(is_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
// libc::ioctl() takes different types on different architectures
|
||||||
|
#[allow(clippy::useless_conversion)]
|
||||||
|
fn query_block_size(f: &mut File, block_size_type: BlockSize) -> std::io::Result<u64> {
|
||||||
|
let mut block_size = 0;
|
||||||
|
let ret = unsafe {
|
||||||
|
ioctl(
|
||||||
|
f.as_raw_fd(),
|
||||||
|
match block_size_type {
|
||||||
|
BlockSize::LogicalBlock => BLKSSZGET(),
|
||||||
|
BlockSize::PhysicalBlock => BLKPBSZGET(),
|
||||||
|
BlockSize::MinimumIo => BLKIOMIN(),
|
||||||
|
BlockSize::OptimalIo => BLKIOOPT(),
|
||||||
|
}
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
&mut block_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ret != 0 {
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(block_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn probe(f: &mut File) -> std::io::Result<Self> {
|
||||||
|
if !Self::is_block_device(f)? {
|
||||||
|
return Ok(DiskTopology::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(DiskTopology {
|
||||||
|
logical_block_size: Self::query_block_size(f, BlockSize::LogicalBlock)?,
|
||||||
|
physical_block_size: Self::query_block_size(f, BlockSize::PhysicalBlock)?,
|
||||||
|
minimum_io_size: Self::query_block_size(f, BlockSize::MinimumIo)?,
|
||||||
|
optimal_io_size: Self::query_block_size(f, BlockSize::OptimalIo)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
pub type DiskFileResult<T> = std::result::Result<T, DiskFileError>;
|
||||||
|
|
||||||
pub trait DiskFile: Send + Sync {
|
pub trait DiskFile: Send + Sync {
|
||||||
fn size(&mut self) -> DiskFileResult<u64>;
|
fn size(&mut self) -> DiskFileResult<u64>;
|
||||||
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
fn new_async_io(&self, ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>>;
|
||||||
|
fn topology(&mut self) -> DiskTopology {
|
||||||
|
DiskTopology::default()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ pub mod raw_sync;
|
|||||||
pub mod vhd;
|
pub mod vhd;
|
||||||
pub mod vhdx_sync;
|
pub mod vhdx_sync;
|
||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult, DiskFileError, DiskFileResult};
|
use crate::async_io::{AsyncIo, AsyncIoError, AsyncIoResult};
|
||||||
#[cfg(feature = "io_uring")]
|
|
||||||
use io_uring::{opcode, IoUring, Probe};
|
use io_uring::{opcode, IoUring, Probe};
|
||||||
|
use std::alloc::{alloc_zeroed, dealloc, Layout};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -30,15 +30,17 @@ use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
|||||||
use std::os::linux::fs::MetadataExt;
|
use std::os::linux::fs::MetadataExt;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
|
use std::sync::MutexGuard;
|
||||||
use versionize::{VersionMap, Versionize, VersionizeResult};
|
use versionize::{VersionMap, Versionize, VersionizeResult};
|
||||||
use versionize_derive::Versionize;
|
use versionize_derive::Versionize;
|
||||||
use virtio_bindings::bindings::virtio_blk::*;
|
use virtio_bindings::bindings::virtio_blk::*;
|
||||||
use virtio_queue::DescriptorChain;
|
use virtio_queue::DescriptorChain;
|
||||||
use vm_memory::{
|
use vm_memory::{
|
||||||
bitmap::AtomicBitmap, bitmap::Bitmap, ByteValued, Bytes, GuestAddress, GuestMemory,
|
bitmap::AtomicBitmap, bitmap::Bitmap, ByteValued, Bytes, GuestAddress, GuestMemory,
|
||||||
GuestMemoryAtomic, GuestMemoryError,
|
GuestMemoryError, GuestMemoryLoadGuard,
|
||||||
};
|
};
|
||||||
|
use vm_virtio::{AccessPlatform, Translatable};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
||||||
@@ -113,6 +115,8 @@ pub enum ExecuteError {
|
|||||||
AsyncRead(AsyncIoError),
|
AsyncRead(AsyncIoError),
|
||||||
AsyncWrite(AsyncIoError),
|
AsyncWrite(AsyncIoError),
|
||||||
AsyncFlush(AsyncIoError),
|
AsyncFlush(AsyncIoError),
|
||||||
|
/// Failed allocating a temporary buffer.
|
||||||
|
TemporaryBufferAllocation(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecuteError {
|
impl ExecuteError {
|
||||||
@@ -129,6 +133,7 @@ impl ExecuteError {
|
|||||||
ExecuteError::AsyncRead(_) => VIRTIO_BLK_S_IOERR,
|
ExecuteError::AsyncRead(_) => VIRTIO_BLK_S_IOERR,
|
||||||
ExecuteError::AsyncWrite(_) => VIRTIO_BLK_S_IOERR,
|
ExecuteError::AsyncWrite(_) => VIRTIO_BLK_S_IOERR,
|
||||||
ExecuteError::AsyncFlush(_) => VIRTIO_BLK_S_IOERR,
|
ExecuteError::AsyncFlush(_) => VIRTIO_BLK_S_IOERR,
|
||||||
|
ExecuteError::TemporaryBufferAllocation(_) => VIRTIO_BLK_S_IOERR,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,6 +171,14 @@ fn sector(mem: &GuestMemoryMmap, desc_addr: GuestAddress) -> result::Result<u64,
|
|||||||
mem.read_obj(addr).map_err(Error::GuestMemory)
|
mem.read_obj(addr).map_err(Error::GuestMemory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AlignedOperation {
|
||||||
|
origin_ptr: u64,
|
||||||
|
aligned_ptr: u64,
|
||||||
|
size: usize,
|
||||||
|
layout: Layout,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Request {
|
pub struct Request {
|
||||||
pub request_type: RequestType,
|
pub request_type: RequestType,
|
||||||
@@ -173,11 +186,13 @@ pub struct Request {
|
|||||||
pub data_descriptors: Vec<(GuestAddress, u32)>,
|
pub data_descriptors: Vec<(GuestAddress, u32)>,
|
||||||
pub status_addr: GuestAddress,
|
pub status_addr: GuestAddress,
|
||||||
pub writeback: bool,
|
pub writeback: bool,
|
||||||
|
pub aligned_operations: Vec<AlignedOperation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
desc_chain: &mut DescriptorChain<GuestMemoryAtomic<GuestMemoryMmap>>,
|
desc_chain: &mut DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap>>,
|
||||||
|
access_platform: Option<&Arc<dyn AccessPlatform>>,
|
||||||
) -> result::Result<Request, Error> {
|
) -> result::Result<Request, Error> {
|
||||||
let hdr_desc = desc_chain
|
let hdr_desc = desc_chain
|
||||||
.next()
|
.next()
|
||||||
@@ -192,12 +207,17 @@ impl Request {
|
|||||||
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
return Err(Error::UnexpectedWriteOnlyDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let hdr_desc_addr = hdr_desc
|
||||||
|
.addr()
|
||||||
|
.translate(access_platform, hdr_desc.len() as usize);
|
||||||
|
|
||||||
let mut req = Request {
|
let mut req = Request {
|
||||||
request_type: request_type(desc_chain.memory(), hdr_desc.addr())?,
|
request_type: request_type(desc_chain.memory(), hdr_desc_addr)?,
|
||||||
sector: sector(desc_chain.memory(), hdr_desc.addr())?,
|
sector: sector(desc_chain.memory(), hdr_desc_addr)?,
|
||||||
data_descriptors: Vec::new(),
|
data_descriptors: Vec::new(),
|
||||||
status_addr: GuestAddress(0),
|
status_addr: GuestAddress(0),
|
||||||
writeback: true,
|
writeback: true,
|
||||||
|
aligned_operations: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let status_desc;
|
let status_desc;
|
||||||
@@ -227,7 +247,11 @@ impl Request {
|
|||||||
if !desc.is_write_only() && req.request_type == RequestType::GetDeviceId {
|
if !desc.is_write_only() && req.request_type == RequestType::GetDeviceId {
|
||||||
return Err(Error::UnexpectedReadOnlyDescriptor);
|
return Err(Error::UnexpectedReadOnlyDescriptor);
|
||||||
}
|
}
|
||||||
req.data_descriptors.push((desc.addr(), desc.len()));
|
|
||||||
|
req.data_descriptors.push((
|
||||||
|
desc.addr().translate(access_platform, desc.len() as usize),
|
||||||
|
desc.len(),
|
||||||
|
));
|
||||||
desc = desc_chain
|
desc = desc_chain
|
||||||
.next()
|
.next()
|
||||||
.ok_or(Error::DescriptorChainTooShort)
|
.ok_or(Error::DescriptorChainTooShort)
|
||||||
@@ -248,18 +272,19 @@ impl Request {
|
|||||||
return Err(Error::DescriptorLengthTooSmall);
|
return Err(Error::DescriptorLengthTooSmall);
|
||||||
}
|
}
|
||||||
|
|
||||||
req.status_addr = status_desc.addr();
|
req.status_addr = status_desc
|
||||||
|
.addr()
|
||||||
|
.translate(access_platform, status_desc.len() as usize);
|
||||||
|
|
||||||
Ok(req)
|
Ok(req)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::ptr_arg)]
|
|
||||||
pub fn execute<T: Seek + Read + Write>(
|
pub fn execute<T: Seek + Read + Write>(
|
||||||
&self,
|
&self,
|
||||||
disk: &mut T,
|
disk: &mut T,
|
||||||
disk_nsectors: u64,
|
disk_nsectors: u64,
|
||||||
mem: &GuestMemoryMmap,
|
mem: &GuestMemoryMmap,
|
||||||
disk_id: &Vec<u8>,
|
disk_id: &[u8],
|
||||||
) -> result::Result<u32, ExecuteError> {
|
) -> result::Result<u32, ExecuteError> {
|
||||||
disk.seek(SeekFrom::Start(self.sector << SECTOR_SHIFT))
|
disk.seek(SeekFrom::Start(self.sector << SECTOR_SHIFT))
|
||||||
.map_err(ExecuteError::Seek)?;
|
.map_err(ExecuteError::Seek)?;
|
||||||
@@ -294,7 +319,7 @@ impl Request {
|
|||||||
if (*data_len as usize) < disk_id.len() {
|
if (*data_len as usize) < disk_id.len() {
|
||||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||||
}
|
}
|
||||||
mem.write_slice(disk_id.as_slice(), *data_addr)
|
mem.write_slice(disk_id, *data_addr)
|
||||||
.map_err(ExecuteError::Write)?;
|
.map_err(ExecuteError::Write)?;
|
||||||
}
|
}
|
||||||
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
|
||||||
@@ -304,7 +329,7 @@ impl Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_async(
|
pub fn execute_async(
|
||||||
&self,
|
&mut self,
|
||||||
mem: &GuestMemoryMmap,
|
mem: &GuestMemoryMmap,
|
||||||
disk_nsectors: u64,
|
disk_nsectors: u64,
|
||||||
disk_image: &mut dyn AsyncIo,
|
disk_image: &mut dyn AsyncIo,
|
||||||
@@ -317,6 +342,9 @@ impl Request {
|
|||||||
|
|
||||||
let mut iovecs = Vec::new();
|
let mut iovecs = Vec::new();
|
||||||
for (data_addr, data_len) in &self.data_descriptors {
|
for (data_addr, data_len) in &self.data_descriptors {
|
||||||
|
if *data_len == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let mut top: u64 = u64::from(*data_len) / SECTOR_SIZE;
|
let mut top: u64 = u64::from(*data_len) / SECTOR_SIZE;
|
||||||
if u64::from(*data_len) % SECTOR_SIZE != 0 {
|
if u64::from(*data_len) % SECTOR_SIZE != 0 {
|
||||||
top += 1;
|
top += 1;
|
||||||
@@ -328,12 +356,52 @@ impl Request {
|
|||||||
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
return Err(ExecuteError::BadRequest(Error::InvalidOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
let buf = mem
|
let origin_ptr = mem
|
||||||
.get_slice(*data_addr, *data_len as usize)
|
.get_slice(*data_addr, *data_len as usize)
|
||||||
.map_err(ExecuteError::GetHostAddress)?
|
.map_err(ExecuteError::GetHostAddress)?
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
|
|
||||||
|
// Verify the buffer alignment.
|
||||||
|
// In case it's not properly aligned, an intermediate buffer is
|
||||||
|
// created with the correct alignment, and a copy from/to the
|
||||||
|
// origin buffer is performed, depending on the type of operation.
|
||||||
|
let iov_base = if (origin_ptr as u64) % SECTOR_SIZE != 0 {
|
||||||
|
let layout =
|
||||||
|
Layout::from_size_align(*data_len as usize, SECTOR_SIZE as usize).unwrap();
|
||||||
|
// Safe because layout has non-zero size
|
||||||
|
let aligned_ptr = unsafe { alloc_zeroed(layout) };
|
||||||
|
if aligned_ptr.is_null() {
|
||||||
|
return Err(ExecuteError::TemporaryBufferAllocation(
|
||||||
|
io::Error::last_os_error(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to perform the copy beforehand in case we're writing
|
||||||
|
// data out.
|
||||||
|
if request_type == RequestType::Out {
|
||||||
|
// Safe because destination buffer has been allocated with
|
||||||
|
// the proper size.
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy(origin_ptr as *const u8, aligned_ptr, *data_len as usize)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store both origin and aligned pointers for complete_async()
|
||||||
|
// to process them.
|
||||||
|
self.aligned_operations.push(AlignedOperation {
|
||||||
|
origin_ptr: origin_ptr as u64,
|
||||||
|
aligned_ptr: aligned_ptr as u64,
|
||||||
|
size: *data_len as usize,
|
||||||
|
layout,
|
||||||
|
});
|
||||||
|
|
||||||
|
aligned_ptr as *mut libc::c_void
|
||||||
|
} else {
|
||||||
|
origin_ptr as *mut libc::c_void
|
||||||
|
};
|
||||||
|
|
||||||
let iovec = libc::iovec {
|
let iovec = libc::iovec {
|
||||||
iov_base: buf as *mut libc::c_void,
|
iov_base,
|
||||||
iov_len: *data_len as libc::size_t,
|
iov_len: *data_len as libc::size_t,
|
||||||
};
|
};
|
||||||
iovecs.push(iovec);
|
iovecs.push(iovec);
|
||||||
@@ -381,6 +449,36 @@ impl Request {
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn complete_async(&mut self) -> result::Result<(), Error> {
|
||||||
|
for aligned_operation in self.aligned_operations.drain(..) {
|
||||||
|
// We need to perform the copy after the data has been read inside
|
||||||
|
// the aligned buffer in case we're reading data in.
|
||||||
|
if self.request_type == RequestType::In {
|
||||||
|
// Safe because origin buffer has been allocated with the
|
||||||
|
// proper size.
|
||||||
|
unsafe {
|
||||||
|
std::ptr::copy(
|
||||||
|
aligned_operation.aligned_ptr as *const u8,
|
||||||
|
aligned_operation.origin_ptr as *mut u8,
|
||||||
|
aligned_operation.size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free the temporary aligned buffer.
|
||||||
|
// Safe because aligned_ptr was allocated by alloc_zeroed with the same
|
||||||
|
// layout
|
||||||
|
unsafe {
|
||||||
|
dealloc(
|
||||||
|
aligned_operation.aligned_ptr as *mut u8,
|
||||||
|
aligned_operation.layout,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_writeback(&mut self, writeback: bool) {
|
pub fn set_writeback(&mut self, writeback: bool) {
|
||||||
self.writeback = writeback
|
self.writeback = writeback
|
||||||
}
|
}
|
||||||
@@ -423,7 +521,6 @@ unsafe impl ByteValued for VirtioBlockGeometry {}
|
|||||||
|
|
||||||
/// Check if io_uring for block device can be used on the current system, as
|
/// Check if io_uring for block device can be used on the current system, as
|
||||||
/// it correctly supports the expected io_uring features.
|
/// it correctly supports the expected io_uring features.
|
||||||
#[cfg(feature = "io_uring")]
|
|
||||||
pub fn block_io_uring_is_supported() -> bool {
|
pub fn block_io_uring_is_supported() -> bool {
|
||||||
let error_msg = "io_uring not supported:";
|
let error_msg = "io_uring not supported:";
|
||||||
|
|
||||||
@@ -471,119 +568,98 @@ pub fn block_io_uring_is_supported() -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "io_uring"))]
|
pub trait AsyncAdaptor<F>
|
||||||
pub fn block_io_uring_is_supported() -> bool {
|
where
|
||||||
false
|
F: Read + Write + Seek,
|
||||||
}
|
{
|
||||||
|
fn read_vectored_sync(
|
||||||
|
&mut self,
|
||||||
|
offset: libc::off_t,
|
||||||
|
iovecs: Vec<libc::iovec>,
|
||||||
|
user_data: u64,
|
||||||
|
eventfd: &EventFd,
|
||||||
|
completion_list: &mut Vec<(u64, i32)>,
|
||||||
|
) -> AsyncIoResult<()> {
|
||||||
|
// Convert libc::iovec into IoSliceMut
|
||||||
|
let mut slices = Vec::new();
|
||||||
|
for iovec in iovecs.iter() {
|
||||||
|
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn disk_size(file: &mut dyn Seek, semaphore: &mut Arc<Mutex<()>>) -> DiskFileResult<u64> {
|
let result = {
|
||||||
// Take the semaphore to ensure other threads are not interacting with
|
let mut file = self.file();
|
||||||
// the underlying file.
|
|
||||||
let _lock = semaphore.lock().unwrap();
|
|
||||||
|
|
||||||
Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64)
|
// Move the cursor to the right offset
|
||||||
}
|
file.seek(SeekFrom::Start(offset as u64))
|
||||||
|
.map_err(AsyncIoError::ReadVectored)?;
|
||||||
|
|
||||||
pub trait ReadSeekFile: Read + Seek {}
|
// Read vectored
|
||||||
impl<F: Read + Seek> ReadSeekFile for F {}
|
file.read_vectored(slices.as_mut_slice())
|
||||||
|
.map_err(AsyncIoError::ReadVectored)?
|
||||||
|
};
|
||||||
|
|
||||||
pub fn read_vectored_sync(
|
completion_list.push((user_data, result as i32));
|
||||||
offset: libc::off_t,
|
|
||||||
iovecs: Vec<libc::iovec>,
|
|
||||||
user_data: u64,
|
|
||||||
file: &mut dyn ReadSeekFile,
|
|
||||||
eventfd: &EventFd,
|
|
||||||
completion_list: &mut Vec<(u64, i32)>,
|
|
||||||
semaphore: &mut Arc<Mutex<()>>,
|
|
||||||
) -> AsyncIoResult<()> {
|
|
||||||
// Convert libc::iovec into IoSliceMut
|
|
||||||
let mut slices = Vec::new();
|
|
||||||
for iovec in iovecs.iter() {
|
|
||||||
slices.push(IoSliceMut::new(unsafe { std::mem::transmute(*iovec) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
// Take the semaphore to ensure other threads are not interacting
|
|
||||||
// with the underlying file.
|
|
||||||
let _lock = semaphore.lock().unwrap();
|
|
||||||
|
|
||||||
// Move the cursor to the right offset
|
|
||||||
file.seek(SeekFrom::Start(offset as u64))
|
|
||||||
.map_err(AsyncIoError::ReadVectored)?;
|
|
||||||
|
|
||||||
// Read vectored
|
|
||||||
file.read_vectored(slices.as_mut_slice())
|
|
||||||
.map_err(AsyncIoError::ReadVectored)?
|
|
||||||
};
|
|
||||||
|
|
||||||
completion_list.push((user_data, result as i32));
|
|
||||||
eventfd.write(1).unwrap();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait WriteSeekFile: Write + Seek {}
|
|
||||||
impl<F: Write + Seek> WriteSeekFile for F {}
|
|
||||||
|
|
||||||
pub fn write_vectored_sync(
|
|
||||||
offset: libc::off_t,
|
|
||||||
iovecs: Vec<libc::iovec>,
|
|
||||||
user_data: u64,
|
|
||||||
file: &mut dyn WriteSeekFile,
|
|
||||||
eventfd: &EventFd,
|
|
||||||
completion_list: &mut Vec<(u64, i32)>,
|
|
||||||
semaphore: &mut Arc<Mutex<()>>,
|
|
||||||
) -> AsyncIoResult<()> {
|
|
||||||
// Convert libc::iovec into IoSlice
|
|
||||||
let mut slices = Vec::new();
|
|
||||||
for iovec in iovecs.iter() {
|
|
||||||
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
let result = {
|
|
||||||
// Take the semaphore to ensure other threads are not interacting
|
|
||||||
// with the underlying file.
|
|
||||||
let _lock = semaphore.lock().unwrap();
|
|
||||||
|
|
||||||
// Move the cursor to the right offset
|
|
||||||
file.seek(SeekFrom::Start(offset as u64))
|
|
||||||
.map_err(AsyncIoError::WriteVectored)?;
|
|
||||||
|
|
||||||
// Write vectored
|
|
||||||
file.write_vectored(slices.as_slice())
|
|
||||||
.map_err(AsyncIoError::WriteVectored)?
|
|
||||||
};
|
|
||||||
|
|
||||||
completion_list.push((user_data, result as i32));
|
|
||||||
eventfd.write(1).unwrap();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fsync_sync(
|
|
||||||
user_data: Option<u64>,
|
|
||||||
file: &mut dyn Write,
|
|
||||||
eventfd: &EventFd,
|
|
||||||
completion_list: &mut Vec<(u64, i32)>,
|
|
||||||
semaphore: &mut Arc<Mutex<()>>,
|
|
||||||
) -> AsyncIoResult<()> {
|
|
||||||
let result: i32 = {
|
|
||||||
// Take the semaphore to ensure other threads are not interacting
|
|
||||||
// with the underlying file.
|
|
||||||
let _lock = semaphore.lock().unwrap();
|
|
||||||
|
|
||||||
// Flush
|
|
||||||
file.flush().map_err(AsyncIoError::Fsync)?;
|
|
||||||
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(user_data) = user_data {
|
|
||||||
completion_list.push((user_data, result));
|
|
||||||
eventfd.write(1).unwrap();
|
eventfd.write(1).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
fn write_vectored_sync(
|
||||||
|
&mut self,
|
||||||
|
offset: libc::off_t,
|
||||||
|
iovecs: Vec<libc::iovec>,
|
||||||
|
user_data: u64,
|
||||||
|
eventfd: &EventFd,
|
||||||
|
completion_list: &mut Vec<(u64, i32)>,
|
||||||
|
) -> AsyncIoResult<()> {
|
||||||
|
// Convert libc::iovec into IoSlice
|
||||||
|
let mut slices = Vec::new();
|
||||||
|
for iovec in iovecs.iter() {
|
||||||
|
slices.push(IoSlice::new(unsafe { std::mem::transmute(*iovec) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = {
|
||||||
|
let mut file = self.file();
|
||||||
|
|
||||||
|
// Move the cursor to the right offset
|
||||||
|
file.seek(SeekFrom::Start(offset as u64))
|
||||||
|
.map_err(AsyncIoError::WriteVectored)?;
|
||||||
|
|
||||||
|
// Write vectored
|
||||||
|
file.write_vectored(slices.as_slice())
|
||||||
|
.map_err(AsyncIoError::WriteVectored)?
|
||||||
|
};
|
||||||
|
|
||||||
|
completion_list.push((user_data, result as i32));
|
||||||
|
eventfd.write(1).unwrap();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fsync_sync(
|
||||||
|
&mut self,
|
||||||
|
user_data: Option<u64>,
|
||||||
|
eventfd: &EventFd,
|
||||||
|
completion_list: &mut Vec<(u64, i32)>,
|
||||||
|
) -> AsyncIoResult<()> {
|
||||||
|
let result: i32 = {
|
||||||
|
let mut file = self.file();
|
||||||
|
|
||||||
|
// Flush
|
||||||
|
file.flush().map_err(AsyncIoError::Fsync)?;
|
||||||
|
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(user_data) = user_data {
|
||||||
|
completion_list.push((user_data, result));
|
||||||
|
eventfd.write(1).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn file(&mut self) -> MutexGuard<F>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ImageType {
|
pub enum ImageType {
|
||||||
|
|||||||
@@ -2,59 +2,61 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileResult};
|
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||||
use crate::{disk_size, fsync_sync, read_vectored_sync, write_vectored_sync};
|
use crate::AsyncAdaptor;
|
||||||
use qcow::{QcowFile, RawFile, Result as QcowResult};
|
use qcow::{QcowFile, RawFile, Result as QcowResult};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::io::{Seek, SeekFrom};
|
||||||
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
pub struct QcowDiskSync {
|
pub struct QcowDiskSync {
|
||||||
qcow_file: QcowFile,
|
qcow_file: Arc<Mutex<QcowFile>>,
|
||||||
semaphore: Arc<Mutex<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QcowDiskSync {
|
impl QcowDiskSync {
|
||||||
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
pub fn new(file: File, direct_io: bool) -> QcowResult<Self> {
|
||||||
Ok(QcowDiskSync {
|
Ok(QcowDiskSync {
|
||||||
qcow_file: QcowFile::from(RawFile::new(file, direct_io))?,
|
qcow_file: Arc::new(Mutex::new(QcowFile::from(RawFile::new(file, direct_io))?)),
|
||||||
semaphore: Arc::new(Mutex::new(())),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiskFile for QcowDiskSync {
|
impl DiskFile for QcowDiskSync {
|
||||||
fn size(&mut self) -> DiskFileResult<u64> {
|
fn size(&mut self) -> DiskFileResult<u64> {
|
||||||
disk_size(&mut self.qcow_file, &mut self.semaphore)
|
let mut file = self.qcow_file.lock().unwrap();
|
||||||
|
|
||||||
|
Ok(file.seek(SeekFrom::End(0)).map_err(DiskFileError::Size)? as u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||||
Ok(Box::new(QcowSync::new(
|
Ok(Box::new(QcowSync::new(self.qcow_file.clone())) as Box<dyn AsyncIo>)
|
||||||
self.qcow_file.clone(),
|
|
||||||
self.semaphore.clone(),
|
|
||||||
)) as Box<dyn AsyncIo>)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct QcowSync {
|
pub struct QcowSync {
|
||||||
qcow_file: QcowFile,
|
qcow_file: Arc<Mutex<QcowFile>>,
|
||||||
eventfd: EventFd,
|
eventfd: EventFd,
|
||||||
completion_list: Vec<(u64, i32)>,
|
completion_list: Vec<(u64, i32)>,
|
||||||
semaphore: Arc<Mutex<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl QcowSync {
|
impl QcowSync {
|
||||||
pub fn new(qcow_file: QcowFile, semaphore: Arc<Mutex<()>>) -> Self {
|
pub fn new(qcow_file: Arc<Mutex<QcowFile>>) -> Self {
|
||||||
QcowSync {
|
QcowSync {
|
||||||
qcow_file,
|
qcow_file,
|
||||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)
|
eventfd: EventFd::new(libc::EFD_NONBLOCK)
|
||||||
.expect("Failed creating EventFd for QcowSync"),
|
.expect("Failed creating EventFd for QcowSync"),
|
||||||
completion_list: Vec::new(),
|
completion_list: Vec::new(),
|
||||||
semaphore,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsyncAdaptor<QcowFile> for Arc<Mutex<QcowFile>> {
|
||||||
|
fn file(&mut self) -> MutexGuard<QcowFile> {
|
||||||
|
self.lock().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsyncIo for QcowSync {
|
impl AsyncIo for QcowSync {
|
||||||
fn notifier(&self) -> &EventFd {
|
fn notifier(&self) -> &EventFd {
|
||||||
&self.eventfd
|
&self.eventfd
|
||||||
@@ -66,14 +68,12 @@ impl AsyncIo for QcowSync {
|
|||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Vec<libc::iovec>,
|
||||||
user_data: u64,
|
user_data: u64,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
read_vectored_sync(
|
self.qcow_file.read_vectored_sync(
|
||||||
offset,
|
offset,
|
||||||
iovecs,
|
iovecs,
|
||||||
user_data,
|
user_data,
|
||||||
&mut self.qcow_file,
|
|
||||||
&self.eventfd,
|
&self.eventfd,
|
||||||
&mut self.completion_list,
|
&mut self.completion_list,
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,25 +83,18 @@ impl AsyncIo for QcowSync {
|
|||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Vec<libc::iovec>,
|
||||||
user_data: u64,
|
user_data: u64,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
write_vectored_sync(
|
self.qcow_file.write_vectored_sync(
|
||||||
offset,
|
offset,
|
||||||
iovecs,
|
iovecs,
|
||||||
user_data,
|
user_data,
|
||||||
&mut self.qcow_file,
|
|
||||||
&self.eventfd,
|
&self.eventfd,
|
||||||
&mut self.completion_list,
|
&mut self.completion_list,
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||||
fsync_sync(
|
self.qcow_file
|
||||||
user_data,
|
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
|
||||||
&mut self.qcow_file,
|
|
||||||
&self.eventfd,
|
|
||||||
&mut self.completion_list,
|
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete(&mut self) -> Vec<(u64, i32)> {
|
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use crate::async_io::{
|
use crate::async_io::{
|
||||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
|
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, DiskTopology,
|
||||||
};
|
};
|
||||||
use io_uring::{opcode, squeue, types, IoUring};
|
use io_uring::{opcode, squeue, types, IoUring};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -35,6 +35,15 @@ impl DiskFile for RawFileDisk {
|
|||||||
.map_err(DiskFileError::NewAsyncIo)?,
|
.map_err(DiskFileError::NewAsyncIo)?,
|
||||||
) as Box<dyn AsyncIo>)
|
) as Box<dyn AsyncIo>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn topology(&mut self) -> DiskTopology {
|
||||||
|
if let Ok(topology) = DiskTopology::probe(&mut self.file) {
|
||||||
|
topology
|
||||||
|
} else {
|
||||||
|
warn!("Unable to get device topology. Using default topology");
|
||||||
|
DiskTopology::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RawFileAsync {
|
pub struct RawFileAsync {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
|
|
||||||
use crate::async_io::{
|
use crate::async_io::{
|
||||||
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult,
|
AsyncIo, AsyncIoError, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult, DiskTopology,
|
||||||
};
|
};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
@@ -31,6 +31,15 @@ impl DiskFile for RawFileDiskSync {
|
|||||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||||
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
|
Ok(Box::new(RawFileSync::new(self.file.as_raw_fd())) as Box<dyn AsyncIo>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn topology(&mut self) -> DiskTopology {
|
||||||
|
if let Ok(topology) = DiskTopology::probe(&mut self.file) {
|
||||||
|
topology
|
||||||
|
} else {
|
||||||
|
warn!("Unable to get device topology. Using default topology");
|
||||||
|
DiskTopology::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RawFileSync {
|
pub struct RawFileSync {
|
||||||
|
|||||||
@@ -3,26 +3,20 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
use crate::async_io::{AsyncIo, AsyncIoResult, DiskFile, DiskFileError, DiskFileResult};
|
||||||
use crate::{fsync_sync, read_vectored_sync, write_vectored_sync};
|
use crate::AsyncAdaptor;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::ops::DerefMut;
|
use std::sync::{Arc, Mutex, MutexGuard};
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
|
use vhdx::vhdx::{Result as VhdxResult, Vhdx};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
pub struct VhdxDiskSync {
|
pub struct VhdxDiskSync {
|
||||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||||
semaphore: Arc<Mutex<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VhdxDiskSync {
|
impl VhdxDiskSync {
|
||||||
pub fn new(f: File) -> VhdxResult<Self> {
|
pub fn new(f: File) -> VhdxResult<Self> {
|
||||||
let vhdx = Vhdx::new(f)?;
|
|
||||||
let vhdx_file = Arc::new(Mutex::new(vhdx));
|
|
||||||
|
|
||||||
Ok(VhdxDiskSync {
|
Ok(VhdxDiskSync {
|
||||||
vhdx_file,
|
vhdx_file: Arc::new(Mutex::new(Vhdx::new(f)?)),
|
||||||
semaphore: Arc::new(Mutex::new(())),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,10 +27,10 @@ impl DiskFile for VhdxDiskSync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
fn new_async_io(&self, _ring_depth: u32) -> DiskFileResult<Box<dyn AsyncIo>> {
|
||||||
Ok(Box::new(
|
Ok(
|
||||||
VhdxSync::new(self.vhdx_file.clone(), self.semaphore.clone())
|
Box::new(VhdxSync::new(self.vhdx_file.clone()).map_err(DiskFileError::NewAsyncIo)?)
|
||||||
.map_err(DiskFileError::NewAsyncIo)?,
|
as Box<dyn AsyncIo>,
|
||||||
) as Box<dyn AsyncIo>)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,20 +38,24 @@ pub struct VhdxSync {
|
|||||||
vhdx_file: Arc<Mutex<Vhdx>>,
|
vhdx_file: Arc<Mutex<Vhdx>>,
|
||||||
eventfd: EventFd,
|
eventfd: EventFd,
|
||||||
completion_list: Vec<(u64, i32)>,
|
completion_list: Vec<(u64, i32)>,
|
||||||
semaphore: Arc<Mutex<()>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VhdxSync {
|
impl VhdxSync {
|
||||||
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>, semaphore: Arc<Mutex<()>>) -> std::io::Result<Self> {
|
pub fn new(vhdx_file: Arc<Mutex<Vhdx>>) -> std::io::Result<Self> {
|
||||||
Ok(VhdxSync {
|
Ok(VhdxSync {
|
||||||
vhdx_file,
|
vhdx_file,
|
||||||
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
|
eventfd: EventFd::new(libc::EFD_NONBLOCK)?,
|
||||||
completion_list: Vec::new(),
|
completion_list: Vec::new(),
|
||||||
semaphore,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsyncAdaptor<Vhdx> for Arc<Mutex<Vhdx>> {
|
||||||
|
fn file(&mut self) -> MutexGuard<Vhdx> {
|
||||||
|
self.lock().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl AsyncIo for VhdxSync {
|
impl AsyncIo for VhdxSync {
|
||||||
fn notifier(&self) -> &EventFd {
|
fn notifier(&self) -> &EventFd {
|
||||||
&self.eventfd
|
&self.eventfd
|
||||||
@@ -69,14 +67,12 @@ impl AsyncIo for VhdxSync {
|
|||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Vec<libc::iovec>,
|
||||||
user_data: u64,
|
user_data: u64,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
read_vectored_sync(
|
self.vhdx_file.read_vectored_sync(
|
||||||
offset,
|
offset,
|
||||||
iovecs,
|
iovecs,
|
||||||
user_data,
|
user_data,
|
||||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
|
||||||
&self.eventfd,
|
&self.eventfd,
|
||||||
&mut self.completion_list,
|
&mut self.completion_list,
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,25 +82,18 @@ impl AsyncIo for VhdxSync {
|
|||||||
iovecs: Vec<libc::iovec>,
|
iovecs: Vec<libc::iovec>,
|
||||||
user_data: u64,
|
user_data: u64,
|
||||||
) -> AsyncIoResult<()> {
|
) -> AsyncIoResult<()> {
|
||||||
write_vectored_sync(
|
self.vhdx_file.write_vectored_sync(
|
||||||
offset,
|
offset,
|
||||||
iovecs,
|
iovecs,
|
||||||
user_data,
|
user_data,
|
||||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
|
||||||
&self.eventfd,
|
&self.eventfd,
|
||||||
&mut self.completion_list,
|
&mut self.completion_list,
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
fn fsync(&mut self, user_data: Option<u64>) -> AsyncIoResult<()> {
|
||||||
fsync_sync(
|
self.vhdx_file
|
||||||
user_data,
|
.fsync_sync(user_data, &self.eventfd, &mut self.completion_list)
|
||||||
self.vhdx_file.lock().unwrap().deref_mut(),
|
|
||||||
&self.eventfd,
|
|
||||||
&mut self.completion_list,
|
|
||||||
&mut self.semaphore,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete(&mut self) -> Vec<(u64, i32)> {
|
fn complete(&mut self) -> Vec<(u64, i32)> {
|
||||||
|
|||||||
@@ -6,17 +6,17 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
arch = { path = "../arch" }
|
arch = { path = "../arch" }
|
||||||
bitflags = "1.3.2"
|
bitflags = "1.3.2"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.6.0"
|
vm-memory = "0.7.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
|
|||||||
@@ -291,14 +291,13 @@ impl Rtc {
|
|||||||
|
|
||||||
impl BusDevice for Rtc {
|
impl BusDevice for Rtc {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
let v;
|
|
||||||
let mut read_ok = true;
|
let mut read_ok = true;
|
||||||
|
|
||||||
if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&offset) {
|
let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&offset) {
|
||||||
let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
|
let index = ((offset - AMBA_ID_LOW) >> 2) as usize;
|
||||||
v = u32::from(PL031_ID[index]);
|
u32::from(PL031_ID[index])
|
||||||
} else {
|
} else {
|
||||||
v = match offset {
|
match offset {
|
||||||
RTCDR => self.get_time(),
|
RTCDR => self.get_time(),
|
||||||
RTCMR => {
|
RTCMR => {
|
||||||
// Even though we are not implementing RTC alarm we return the last value
|
// Even though we are not implementing RTC alarm we return the last value
|
||||||
@@ -313,8 +312,8 @@ impl BusDevice for Rtc {
|
|||||||
read_ok = false;
|
read_ok = false;
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
};
|
||||||
if read_ok && data.len() <= 4 {
|
if read_ok && data.len() <= 4 {
|
||||||
write_le_u32(data, v);
|
write_le_u32(data, v);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -294,19 +294,15 @@ impl Pl011 {
|
|||||||
|
|
||||||
impl BusDevice for Pl011 {
|
impl BusDevice for Pl011 {
|
||||||
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
fn read(&mut self, _base: u64, offset: u64, data: &mut [u8]) {
|
||||||
let v;
|
|
||||||
let mut read_ok = true;
|
let mut read_ok = true;
|
||||||
if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&(offset >> 2)) {
|
let v = if (AMBA_ID_LOW..AMBA_ID_HIGH).contains(&(offset >> 2)) {
|
||||||
let index = ((offset - 0xfe0) >> 2) as usize;
|
let index = ((offset - 0xfe0) >> 2) as usize;
|
||||||
v = u32::from(PL011_ID[index]);
|
u32::from(PL011_ID[index])
|
||||||
} else {
|
} else {
|
||||||
v = match offset >> 2 {
|
match offset >> 2 {
|
||||||
UARTDR => {
|
UARTDR => {
|
||||||
let c: u32;
|
|
||||||
let r: u32;
|
|
||||||
|
|
||||||
self.flags &= !PL011_FLAG_RXFF;
|
self.flags &= !PL011_FLAG_RXFF;
|
||||||
c = self.read_fifo.pop_front().unwrap_or_default().into();
|
let c: u32 = self.read_fifo.pop_front().unwrap_or_default().into();
|
||||||
if self.read_count > 0 {
|
if self.read_count > 0 {
|
||||||
self.read_count -= 1;
|
self.read_count -= 1;
|
||||||
}
|
}
|
||||||
@@ -317,8 +313,7 @@ impl BusDevice for Pl011 {
|
|||||||
self.int_level &= !PL011_INT_RX;
|
self.int_level &= !PL011_INT_RX;
|
||||||
}
|
}
|
||||||
self.rsr = c >> 8;
|
self.rsr = c >> 8;
|
||||||
r = c;
|
c
|
||||||
r
|
|
||||||
}
|
}
|
||||||
UARTRSR_UARTECR => self.rsr,
|
UARTRSR_UARTECR => self.rsr,
|
||||||
UARTFR => self.flags,
|
UARTFR => self.flags,
|
||||||
@@ -337,7 +332,7 @@ impl BusDevice for Pl011 {
|
|||||||
0
|
0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
if read_ok && data.len() <= 4 {
|
if read_ok && data.len() <= 4 {
|
||||||
write_le_u32(data, v);
|
write_le_u32(data, v);
|
||||||
|
|||||||
399
docs/COPYING.docs
Normal file
399
docs/COPYING.docs
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
The documentation in this directory is covered by the following license:
|
||||||
|
|
||||||
|
Attribution 4.0 International
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||||
|
does not provide legal services or legal advice. Distribution of
|
||||||
|
Creative Commons public licenses does not create a lawyer-client or
|
||||||
|
other relationship. Creative Commons makes its licenses and related
|
||||||
|
information available on an "as-is" basis. Creative Commons gives no
|
||||||
|
warranties regarding its licenses, any material licensed under their
|
||||||
|
terms and conditions, or any related information. Creative Commons
|
||||||
|
disclaims all liability for damages resulting from their use to the
|
||||||
|
fullest extent possible.
|
||||||
|
|
||||||
|
Using Creative Commons Public Licenses
|
||||||
|
|
||||||
|
Creative Commons public licenses provide a standard set of terms and
|
||||||
|
conditions that creators and other rights holders may use to share
|
||||||
|
original works of authorship and other material subject to copyright
|
||||||
|
and certain other rights specified in the public license below. The
|
||||||
|
following considerations are for informational purposes only, are not
|
||||||
|
exhaustive, and do not form part of our licenses.
|
||||||
|
|
||||||
|
Considerations for licensors: Our public licenses are
|
||||||
|
intended for use by those authorized to give the public
|
||||||
|
permission to use material in ways otherwise restricted by
|
||||||
|
copyright and certain other rights. Our licenses are
|
||||||
|
irrevocable. Licensors should read and understand the terms
|
||||||
|
and conditions of the license they choose before applying it.
|
||||||
|
Licensors should also secure all rights necessary before
|
||||||
|
applying our licenses so that the public can reuse the
|
||||||
|
material as expected. Licensors should clearly mark any
|
||||||
|
material not subject to the license. This includes other CC-
|
||||||
|
licensed material, or material used under an exception or
|
||||||
|
limitation to copyright. More considerations for licensors:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensors
|
||||||
|
|
||||||
|
Considerations for the public: By using one of our public
|
||||||
|
licenses, a licensor grants the public permission to use the
|
||||||
|
licensed material under specified terms and conditions. If
|
||||||
|
the licensor's permission is not necessary for any reason--for
|
||||||
|
example, because of any applicable exception or limitation to
|
||||||
|
copyright--then that use is not regulated by the license. Our
|
||||||
|
licenses grant only permissions under copyright and certain
|
||||||
|
other rights that a licensor has authority to grant. Use of
|
||||||
|
the licensed material may still be restricted for other
|
||||||
|
reasons, including because others have copyright or other
|
||||||
|
rights in the material. A licensor may make special requests,
|
||||||
|
such as asking that all changes be marked or described.
|
||||||
|
Although not required by our licenses, you are encouraged to
|
||||||
|
respect those requests where reasonable. More considerations
|
||||||
|
for the public:
|
||||||
|
wiki.creativecommons.org/Considerations_for_licensees
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons Attribution 4.0 International Public License
|
||||||
|
|
||||||
|
By exercising the Licensed Rights (defined below), You accept and agree
|
||||||
|
to be bound by the terms and conditions of this Creative Commons
|
||||||
|
Attribution 4.0 International Public License ("Public License"). To the
|
||||||
|
extent this Public License may be interpreted as a contract, You are
|
||||||
|
granted the Licensed Rights in consideration of Your acceptance of
|
||||||
|
these terms and conditions, and the Licensor grants You such rights in
|
||||||
|
consideration of benefits the Licensor receives from making the
|
||||||
|
Licensed Material available under these terms and conditions.
|
||||||
|
|
||||||
|
|
||||||
|
Section 1 -- Definitions.
|
||||||
|
|
||||||
|
a. Adapted Material means material subject to Copyright and Similar
|
||||||
|
Rights that is derived from or based upon the Licensed Material
|
||||||
|
and in which the Licensed Material is translated, altered,
|
||||||
|
arranged, transformed, or otherwise modified in a manner requiring
|
||||||
|
permission under the Copyright and Similar Rights held by the
|
||||||
|
Licensor. For purposes of this Public License, where the Licensed
|
||||||
|
Material is a musical work, performance, or sound recording,
|
||||||
|
Adapted Material is always produced where the Licensed Material is
|
||||||
|
synched in timed relation with a moving image.
|
||||||
|
|
||||||
|
b. Adapter's License means the license You apply to Your Copyright
|
||||||
|
and Similar Rights in Your contributions to Adapted Material in
|
||||||
|
accordance with the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||||
|
closely related to copyright including, without limitation,
|
||||||
|
performance, broadcast, sound recording, and Sui Generis Database
|
||||||
|
Rights, without regard to how the rights are labeled or
|
||||||
|
categorized. For purposes of this Public License, the rights
|
||||||
|
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||||
|
Rights.
|
||||||
|
|
||||||
|
d. Effective Technological Measures means those measures that, in the
|
||||||
|
absence of proper authority, may not be circumvented under laws
|
||||||
|
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||||
|
Treaty adopted on December 20, 1996, and/or similar international
|
||||||
|
agreements.
|
||||||
|
|
||||||
|
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||||
|
any other exception or limitation to Copyright and Similar Rights
|
||||||
|
that applies to Your use of the Licensed Material.
|
||||||
|
|
||||||
|
f. Licensed Material means the artistic or literary work, database,
|
||||||
|
or other material to which the Licensor applied this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
g. Licensed Rights means the rights granted to You subject to the
|
||||||
|
terms and conditions of this Public License, which are limited to
|
||||||
|
all Copyright and Similar Rights that apply to Your use of the
|
||||||
|
Licensed Material and that the Licensor has authority to license.
|
||||||
|
|
||||||
|
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||||
|
under this Public License.
|
||||||
|
|
||||||
|
i. Share means to provide material to the public by any means or
|
||||||
|
process that requires permission under the Licensed Rights, such
|
||||||
|
as reproduction, public display, public performance, distribution,
|
||||||
|
dissemination, communication, or importation, and to make material
|
||||||
|
available to the public including in ways that members of the
|
||||||
|
public may access the material from a place and at a time
|
||||||
|
individually chosen by them.
|
||||||
|
|
||||||
|
j. Sui Generis Database Rights means rights other than copyright
|
||||||
|
resulting from Directive 96/9/EC of the European Parliament and of
|
||||||
|
the Council of 11 March 1996 on the legal protection of databases,
|
||||||
|
as amended and/or succeeded, as well as other essentially
|
||||||
|
equivalent rights anywhere in the world.
|
||||||
|
|
||||||
|
k. You means the individual or entity exercising the Licensed Rights
|
||||||
|
under this Public License. Your has a corresponding meaning.
|
||||||
|
|
||||||
|
|
||||||
|
Section 2 -- Scope.
|
||||||
|
|
||||||
|
a. License grant.
|
||||||
|
|
||||||
|
1. Subject to the terms and conditions of this Public License,
|
||||||
|
the Licensor hereby grants You a worldwide, royalty-free,
|
||||||
|
non-sublicensable, non-exclusive, irrevocable license to
|
||||||
|
exercise the Licensed Rights in the Licensed Material to:
|
||||||
|
|
||||||
|
a. reproduce and Share the Licensed Material, in whole or
|
||||||
|
in part; and
|
||||||
|
|
||||||
|
b. produce, reproduce, and Share Adapted Material.
|
||||||
|
|
||||||
|
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||||
|
Exceptions and Limitations apply to Your use, this Public
|
||||||
|
License does not apply, and You do not need to comply with
|
||||||
|
its terms and conditions.
|
||||||
|
|
||||||
|
3. Term. The term of this Public License is specified in Section
|
||||||
|
6(a).
|
||||||
|
|
||||||
|
4. Media and formats; technical modifications allowed. The
|
||||||
|
Licensor authorizes You to exercise the Licensed Rights in
|
||||||
|
all media and formats whether now known or hereafter created,
|
||||||
|
and to make technical modifications necessary to do so. The
|
||||||
|
Licensor waives and/or agrees not to assert any right or
|
||||||
|
authority to forbid You from making technical modifications
|
||||||
|
necessary to exercise the Licensed Rights, including
|
||||||
|
technical modifications necessary to circumvent Effective
|
||||||
|
Technological Measures. For purposes of this Public License,
|
||||||
|
simply making modifications authorized by this Section 2(a)
|
||||||
|
(4) never produces Adapted Material.
|
||||||
|
|
||||||
|
5. Downstream recipients.
|
||||||
|
|
||||||
|
a. Offer from the Licensor -- Licensed Material. Every
|
||||||
|
recipient of the Licensed Material automatically
|
||||||
|
receives an offer from the Licensor to exercise the
|
||||||
|
Licensed Rights under the terms and conditions of this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
b. No downstream restrictions. You may not offer or impose
|
||||||
|
any additional or different terms or conditions on, or
|
||||||
|
apply any Effective Technological Measures to, the
|
||||||
|
Licensed Material if doing so restricts exercise of the
|
||||||
|
Licensed Rights by any recipient of the Licensed
|
||||||
|
Material.
|
||||||
|
|
||||||
|
6. No endorsement. Nothing in this Public License constitutes or
|
||||||
|
may be construed as permission to assert or imply that You
|
||||||
|
are, or that Your use of the Licensed Material is, connected
|
||||||
|
with, or sponsored, endorsed, or granted official status by,
|
||||||
|
the Licensor or others designated to receive attribution as
|
||||||
|
provided in Section 3(a)(1)(A)(i).
|
||||||
|
|
||||||
|
b. Other rights.
|
||||||
|
|
||||||
|
1. Moral rights, such as the right of integrity, are not
|
||||||
|
licensed under this Public License, nor are publicity,
|
||||||
|
privacy, and/or other similar personality rights; however, to
|
||||||
|
the extent possible, the Licensor waives and/or agrees not to
|
||||||
|
assert any such rights held by the Licensor to the limited
|
||||||
|
extent necessary to allow You to exercise the Licensed
|
||||||
|
Rights, but not otherwise.
|
||||||
|
|
||||||
|
2. Patent and trademark rights are not licensed under this
|
||||||
|
Public License.
|
||||||
|
|
||||||
|
3. To the extent possible, the Licensor waives any right to
|
||||||
|
collect royalties from You for the exercise of the Licensed
|
||||||
|
Rights, whether directly or through a collecting society
|
||||||
|
under any voluntary or waivable statutory or compulsory
|
||||||
|
licensing scheme. In all other cases the Licensor expressly
|
||||||
|
reserves any right to collect such royalties.
|
||||||
|
|
||||||
|
|
||||||
|
Section 3 -- License Conditions.
|
||||||
|
|
||||||
|
Your exercise of the Licensed Rights is expressly made subject to the
|
||||||
|
following conditions.
|
||||||
|
|
||||||
|
a. Attribution.
|
||||||
|
|
||||||
|
1. If You Share the Licensed Material (including in modified
|
||||||
|
form), You must:
|
||||||
|
|
||||||
|
a. retain the following if it is supplied by the Licensor
|
||||||
|
with the Licensed Material:
|
||||||
|
|
||||||
|
i. identification of the creator(s) of the Licensed
|
||||||
|
Material and any others designated to receive
|
||||||
|
attribution, in any reasonable manner requested by
|
||||||
|
the Licensor (including by pseudonym if
|
||||||
|
designated);
|
||||||
|
|
||||||
|
ii. a copyright notice;
|
||||||
|
|
||||||
|
iii. a notice that refers to this Public License;
|
||||||
|
|
||||||
|
iv. a notice that refers to the disclaimer of
|
||||||
|
warranties;
|
||||||
|
|
||||||
|
v. a URI or hyperlink to the Licensed Material to the
|
||||||
|
extent reasonably practicable;
|
||||||
|
|
||||||
|
b. indicate if You modified the Licensed Material and
|
||||||
|
retain an indication of any previous modifications; and
|
||||||
|
|
||||||
|
c. indicate the Licensed Material is licensed under this
|
||||||
|
Public License, and include the text of, or the URI or
|
||||||
|
hyperlink to, this Public License.
|
||||||
|
|
||||||
|
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||||
|
reasonable manner based on the medium, means, and context in
|
||||||
|
which You Share the Licensed Material. For example, it may be
|
||||||
|
reasonable to satisfy the conditions by providing a URI or
|
||||||
|
hyperlink to a resource that includes the required
|
||||||
|
information.
|
||||||
|
|
||||||
|
3. If requested by the Licensor, You must remove any of the
|
||||||
|
information required by Section 3(a)(1)(A) to the extent
|
||||||
|
reasonably practicable.
|
||||||
|
|
||||||
|
4. If You Share Adapted Material You produce, the Adapter's
|
||||||
|
License You apply must not prevent recipients of the Adapted
|
||||||
|
Material from complying with this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 4 -- Sui Generis Database Rights.
|
||||||
|
|
||||||
|
Where the Licensed Rights include Sui Generis Database Rights that
|
||||||
|
apply to Your use of the Licensed Material:
|
||||||
|
|
||||||
|
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||||
|
to extract, reuse, reproduce, and Share all or a substantial
|
||||||
|
portion of the contents of the database;
|
||||||
|
|
||||||
|
b. if You include all or a substantial portion of the database
|
||||||
|
contents in a database in which You have Sui Generis Database
|
||||||
|
Rights, then the database in which You have Sui Generis Database
|
||||||
|
Rights (but not its individual contents) is Adapted Material; and
|
||||||
|
|
||||||
|
c. You must comply with the conditions in Section 3(a) if You Share
|
||||||
|
all or a substantial portion of the contents of the database.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 4 supplements and does not
|
||||||
|
replace Your obligations under this Public License where the Licensed
|
||||||
|
Rights include other Copyright and Similar Rights.
|
||||||
|
|
||||||
|
|
||||||
|
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||||
|
|
||||||
|
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||||
|
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||||
|
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||||
|
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||||
|
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||||
|
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||||
|
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||||
|
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||||
|
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||||
|
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||||
|
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||||
|
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||||
|
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||||
|
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||||
|
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||||
|
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
c. The disclaimer of warranties and limitation of liability provided
|
||||||
|
above shall be interpreted in a manner that, to the extent
|
||||||
|
possible, most closely approximates an absolute disclaimer and
|
||||||
|
waiver of all liability.
|
||||||
|
|
||||||
|
|
||||||
|
Section 6 -- Term and Termination.
|
||||||
|
|
||||||
|
a. This Public License applies for the term of the Copyright and
|
||||||
|
Similar Rights licensed here. However, if You fail to comply with
|
||||||
|
this Public License, then Your rights under this Public License
|
||||||
|
terminate automatically.
|
||||||
|
|
||||||
|
b. Where Your right to use the Licensed Material has terminated under
|
||||||
|
Section 6(a), it reinstates:
|
||||||
|
|
||||||
|
1. automatically as of the date the violation is cured, provided
|
||||||
|
it is cured within 30 days of Your discovery of the
|
||||||
|
violation; or
|
||||||
|
|
||||||
|
2. upon express reinstatement by the Licensor.
|
||||||
|
|
||||||
|
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||||
|
right the Licensor may have to seek remedies for Your violations
|
||||||
|
of this Public License.
|
||||||
|
|
||||||
|
c. For the avoidance of doubt, the Licensor may also offer the
|
||||||
|
Licensed Material under separate terms or conditions or stop
|
||||||
|
distributing the Licensed Material at any time; however, doing so
|
||||||
|
will not terminate this Public License.
|
||||||
|
|
||||||
|
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||||
|
License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 7 -- Other Terms and Conditions.
|
||||||
|
|
||||||
|
a. The Licensor shall not be bound by any additional or different
|
||||||
|
terms or conditions communicated by You unless expressly agreed.
|
||||||
|
|
||||||
|
b. Any arrangements, understandings, or agreements regarding the
|
||||||
|
Licensed Material not stated herein are separate from and
|
||||||
|
independent of the terms and conditions of this Public License.
|
||||||
|
|
||||||
|
|
||||||
|
Section 8 -- Interpretation.
|
||||||
|
|
||||||
|
a. For the avoidance of doubt, this Public License does not, and
|
||||||
|
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||||
|
conditions on any use of the Licensed Material that could lawfully
|
||||||
|
be made without permission under this Public License.
|
||||||
|
|
||||||
|
b. To the extent possible, if any provision of this Public License is
|
||||||
|
deemed unenforceable, it shall be automatically reformed to the
|
||||||
|
minimum extent necessary to make it enforceable. If the provision
|
||||||
|
cannot be reformed, it shall be severed from this Public License
|
||||||
|
without affecting the enforceability of the remaining terms and
|
||||||
|
conditions.
|
||||||
|
|
||||||
|
c. No term or condition of this Public License will be waived and no
|
||||||
|
failure to comply consented to unless expressly agreed to by the
|
||||||
|
Licensor.
|
||||||
|
|
||||||
|
d. Nothing in this Public License constitutes or may be interpreted
|
||||||
|
as a limitation upon, or waiver of, any privileges and immunities
|
||||||
|
that apply to the Licensor or You, including from the legal
|
||||||
|
processes of any jurisdiction or authority.
|
||||||
|
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Creative Commons is not a party to its public
|
||||||
|
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||||
|
its public licenses to material it publishes and in those instances
|
||||||
|
will be considered the “Licensor.” The text of the Creative Commons
|
||||||
|
public licenses is dedicated to the public domain under the CC0 Public
|
||||||
|
Domain Dedication. Except for the limited purpose of indicating that
|
||||||
|
material is shared under a Creative Commons public license or as
|
||||||
|
otherwise permitted by the Creative Commons policies published at
|
||||||
|
creativecommons.org/policies, Creative Commons does not authorize the
|
||||||
|
use of the trademark "Creative Commons" or any other trademark or logo
|
||||||
|
of Creative Commons without its prior written consent including,
|
||||||
|
without limitation, in connection with any unauthorized modifications
|
||||||
|
to any of its public licenses or any other arrangements,
|
||||||
|
understandings, or agreements concerning use of licensed material. For
|
||||||
|
the avoidance of doubt, this paragraph does not form part of the
|
||||||
|
public licenses.
|
||||||
|
|
||||||
|
Creative Commons may be contacted at creativecommons.org.
|
||||||
|
|
||||||
|
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
# How to build and test Cloud Hypervisor on AArch64
|
# How to build and test Cloud Hypervisor on AArch64
|
||||||
|
|
||||||
This document introduces how to build and test Cloud Hypervisor on AArch64
|
This document introduces how to build and test Cloud Hypervisor on AArch64.
|
||||||
servers. Currently Cloud Hypervisor cannot be tested on Raspberry PI. Because
|
Currently, Cloud Hypervisor supports 2 methods of booting on AArch64: UEFI
|
||||||
on AArch64, Cloud Hypervisor requires GICv3-ITS device for PCIe MSI interrupt
|
booting and direct-kernel booting. The document covers both methods.
|
||||||
handling. But GICv3-ITS has not been equipped on any Raspberry PI product so
|
|
||||||
far.
|
|
||||||
|
|
||||||
Now Cloud Hypervisor supports 2 ways of booting on AArch64: UEFI booting and
|
|
||||||
direct-kernel booting. The document covers both of the ways.
|
|
||||||
|
|
||||||
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM
|
All the steps are based on Ubuntu. We use the Ubuntu cloud image for guest VM
|
||||||
disk.
|
disk.
|
||||||
|
|
||||||
|
## Hardware requirements
|
||||||
|
|
||||||
|
- AArch64 servers (recommended) or development boards equipped with the GICv3
|
||||||
|
interrupt controller.
|
||||||
|
|
||||||
|
- On development boards that have constrained RAM resources, if the creation of
|
||||||
|
a VM consumes a large portion of the free memory on the host, it may be required
|
||||||
|
to enable swap. For example, this was required on a board with 3 GB of RAM
|
||||||
|
booting a 2 GB VM at a point in time when 2.8 GB were free. Without enabling
|
||||||
|
swap the `cloud-hypervisor` process was terminated by the OOM killer. In this
|
||||||
|
situation memory was allocated for the virtual machine using memfd while the
|
||||||
|
page cache was filled, leading to a situation where the kernel could not even
|
||||||
|
drop caches. Making a small section of swap available (observably, 1 to 15 MB),
|
||||||
|
this situation can be resolved and the resulting memory footprint of
|
||||||
|
`cloud-hypervisor` is as expected.
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
|
We create a folder to build and run Cloud Hypervisor at `$HOME/cloud-hypervisor`
|
||||||
|
|||||||
@@ -89,7 +89,9 @@ feature is enabled by default.
|
|||||||
## Virtio devices
|
## Virtio devices
|
||||||
|
|
||||||
For all virtio devices listed below, only `virtio-pci` transport layer is
|
For all virtio devices listed below, only `virtio-pci` transport layer is
|
||||||
supported.
|
supported. Cloud Hypervisor supports multiple PCI segments, and users can
|
||||||
|
append `,pci_segment=<PCI_segment_number>` to the device flag in the Cloud
|
||||||
|
Hypervisor command line to assign devices to a specific PCI segment.
|
||||||
|
|
||||||
### virtio-block
|
### virtio-block
|
||||||
|
|
||||||
|
|||||||
16
docs/fs.md
16
docs/fs.md
@@ -12,12 +12,12 @@ This virtual device relies on the _vhost-user_ protocol, which assumes the backe
|
|||||||
|
|
||||||
_Build virtiofsd_
|
_Build virtiofsd_
|
||||||
```bash
|
```bash
|
||||||
git clone --depth 1 "https://gitlab.com/virtio-fs/qemu.git" -b "qemu5.0-virtiofs-dax" $VIRTIOFSD_DIR
|
git clone https://gitlab.com/virtio-fs/virtiofsd
|
||||||
cd $VIRTIOFSD_DIR
|
pushd virtiofsd
|
||||||
./configure --prefix=$PWD --target-list=x86_64-softmmu
|
cargo build --release
|
||||||
make virtiofsd -j `nproc`
|
sudo setcap cap_sys_admin+epi target/release/virtiofsd
|
||||||
sudo setcap cap_sys_admin+epi "virtiofsd"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
_Create shared directory_
|
_Create shared directory_
|
||||||
```bash
|
```bash
|
||||||
mkdir /tmp/shared_dir
|
mkdir /tmp/shared_dir
|
||||||
@@ -27,11 +27,11 @@ _Run virtiofsd_
|
|||||||
./virtiofsd \
|
./virtiofsd \
|
||||||
-d \
|
-d \
|
||||||
--socket-path=/tmp/virtiofs \
|
--socket-path=/tmp/virtiofs \
|
||||||
-o source=/tmp/shared_dir \
|
--shared-dir=/tmp/shared_dir \
|
||||||
-o cache=none
|
--cache=never
|
||||||
```
|
```
|
||||||
|
|
||||||
The `cache=none` option should be the default when using `virtiofsd` with the __cloud-hypervisor__ VMM. This prevents from using the guest page cache, which reduces the memory footprint of the guest. When running multiple virtual machines on the same host, this will let the host deal with page cache, which will increase the density of virtual machines which can be launched.
|
The `cache=never` option should be the default when using `virtiofsd` with the __cloud-hypervisor__ VMM. This prevents from using the guest page cache, which reduces the memory footprint of the guest. When running multiple virtual machines on the same host, this will let the host deal with page cache, which will increase the density of virtual machines which can be launched.
|
||||||
|
|
||||||
The `cache=always` option will allow for the guest page cache to be used, which will increase the memory footprint of the guest. This option should be used only for specific use cases where a single VM is going to be running on a host.
|
The `cache=always` option will allow for the guest page cache to be used, which will increase the memory footprint of the guest. This option should be used only for specific use cases where a single VM is going to be running on a host.
|
||||||
|
|
||||||
|
|||||||
47
docs/gdb.md
Normal file
47
docs/gdb.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# GDB Support
|
||||||
|
|
||||||
|
This feature allows remote guest debugging using GDB. Note that this feature is only supported on x86_64/KVM.
|
||||||
|
|
||||||
|
To enable debugging with GDB, build with the `gdb` feature enabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo build --features gdb
|
||||||
|
```
|
||||||
|
|
||||||
|
To use the `--gdb` option, specify the Unix Domain Socket with `--path` that Cloud Hypervisor will use to communicate with the host's GDB:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./cloud-hypervisor \
|
||||||
|
--kernel hypervisor-fw \
|
||||||
|
--disk path=bionic-server-cloudimg-amd64.raw \
|
||||||
|
--cpus boot=1 \
|
||||||
|
--memory size=1024M \
|
||||||
|
--net "tap=,mac=,ip=,mask=" \
|
||||||
|
--console off \
|
||||||
|
--serial tty \
|
||||||
|
--gdb path=/tmp/ch-gdb-sock
|
||||||
|
```
|
||||||
|
|
||||||
|
Cloud Hypervisor will listen for GDB on the host side before starting the guest.
|
||||||
|
On the host side, connect to the GDB remote server as follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gdb -q
|
||||||
|
(gdb) target remote /tmp/ch-gdb-sock
|
||||||
|
Remote debugging using /tmp/ch-gdb-sock
|
||||||
|
warning: No executable has been specified, and target does not support
|
||||||
|
determining executable automatically. Try using the "file" command.
|
||||||
|
0x000000000011217e in ?? ()
|
||||||
|
```
|
||||||
|
|
||||||
|
You can set up to four hardware breakpoints using the x86 debug register:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
(gdb) hb *0x1121b7
|
||||||
|
Hardware assisted breakpoint 1 at 0x1121b7
|
||||||
|
(gdb) c
|
||||||
|
Continuing.
|
||||||
|
|
||||||
|
Breakpoint 1, 0x00000000001121b7 in ?? ()
|
||||||
|
(gdb)
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Cloud Hypervisor Hot Plug
|
# Cloud Hypervisor Hot Plug
|
||||||
|
|
||||||
Currently Cloud Hypervisor only supports hot plugging of CPU devices.
|
Currently Cloud Hypervisor supports hot plugging of CPUs devices (x86 only), PCI devices and memory resizing.
|
||||||
|
|
||||||
## Kernel support
|
## Kernel support
|
||||||
|
|
||||||
|
|||||||
@@ -15,14 +15,20 @@ the guest side can be found in the [Guest TDX tree](https://github.com/intel/tdx
|
|||||||
The TDVF firmware can be found in the
|
The TDVF firmware can be found in the
|
||||||
[EDK2 staging project](https://github.com/tianocore/edk2-staging/tree/TDVF).
|
[EDK2 staging project](https://github.com/tianocore/edk2-staging/tree/TDVF).
|
||||||
|
|
||||||
|
The TDShim firmware can be found in the
|
||||||
|
[Confidential Containers project](https://github.com/confidential-containers/td-shim).
|
||||||
|
|
||||||
## Cloud Hypervisor support
|
## Cloud Hypervisor support
|
||||||
|
|
||||||
First, you must be running on a machine with TDX enabled in hardware, and
|
First, you must be running on a machine with TDX enabled in hardware, and
|
||||||
with the host OS compiled from the [KVM TDX tree](https://github.com/intel/tdx/tree/kvm).
|
with the host OS compiled from the [KVM TDX tree](https://github.com/intel/tdx/tree/kvm).
|
||||||
|
|
||||||
Cloud Hypervisor can run TDX VM (Trust Domain) by loading the TDVF firmware,
|
Cloud Hypervisor can run TDX VM (Trust Domain) by loading a TD firmware,
|
||||||
which will then load the guest kernel from the image. The image must be custom
|
which will then load the guest kernel from the image. The image must be custom
|
||||||
as it must include a kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
as it must include a kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
||||||
|
|
||||||
|
### TDVF
|
||||||
|
|
||||||
The firmware can be built as follows:
|
The firmware can be built as follows:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -73,3 +79,26 @@ guest kernel command line contains `console=ttyS0`):
|
|||||||
--serial tty \
|
--serial tty \
|
||||||
--console off
|
--console off
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### TDShim
|
||||||
|
|
||||||
|
This is a lightweight version of the TDVF, written in Rust and designed for
|
||||||
|
direct kernel boot, which is useful for containers use cases.
|
||||||
|
|
||||||
|
You can find the instructions for building the firmware directly from the
|
||||||
|
project [documentation](https://github.com/confidential-containers/td-shim/tree/staging#how-to-build).
|
||||||
|
|
||||||
|
And run a TDX VM by providing the firmware previously built, along with a guest
|
||||||
|
kernel built from the [Guest TDX tree](https://github.com/intel/tdx/tree/guest).
|
||||||
|
The appropriate kernel boot options must be provided through the `--cmdline`
|
||||||
|
option as well.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./cloud-hypervisor \
|
||||||
|
--tdx firmware=tdshim \
|
||||||
|
--kernel bzImage \
|
||||||
|
--cmdline "root=/dev/vda1 console=hvc0 rw tdx_allow_acpi=MCFG"
|
||||||
|
--cpus boot=1 \
|
||||||
|
--memory size=1G \
|
||||||
|
--disk path=tdx_guest_img
|
||||||
|
```
|
||||||
@@ -8,13 +8,13 @@ support in Cloud Hypervisor:
|
|||||||
1. nested-vm migration - migrating between two nested VMs whose host VMs
|
1. nested-vm migration - migrating between two nested VMs whose host VMs
|
||||||
are running on the same machine.
|
are running on the same machine.
|
||||||
|
|
||||||
## Local Migration
|
## Local Migration (Suitable for Live Upgrade of VMM)
|
||||||
Launch the source VM (on the host machine):
|
Launch the source VM (on the host machine):
|
||||||
```bash
|
```bash
|
||||||
$ target/release/cloud-hypervisor
|
$ target/release/cloud-hypervisor
|
||||||
--kernel ~/workloads/vmlinux \
|
--kernel ~/workloads/vmlinux \
|
||||||
--disk path=~/workloads/focal.raw \
|
--disk path=~/workloads/focal.raw \
|
||||||
--cpus boot=1 --memory size=1G \
|
--cpus boot=1 --memory size=1G,shared=on \
|
||||||
--cmdline "root=/dev/vda1 console=ttyS0" \
|
--cmdline "root=/dev/vda1 console=ttyS0" \
|
||||||
--serial tty --console off --api-socket=/tmp/api1
|
--serial tty --console off --api-socket=/tmp/api1
|
||||||
```
|
```
|
||||||
@@ -31,7 +31,7 @@ $ target/release/ch-remote --api-socket=/tmp/api2 receive-migration unix:/tmp/so
|
|||||||
|
|
||||||
Start to send migration for the source VM (on the host machine):
|
Start to send migration for the source VM (on the host machine):
|
||||||
```bash
|
```bash
|
||||||
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration unix:/tmp/sock
|
$ target/release/ch-remote --api-socket=/tmp/api1 send-migration --local unix:/tmp/sock
|
||||||
```
|
```
|
||||||
|
|
||||||
When the above commands completed, the source VM should be successfully
|
When the above commands completed, the source VM should be successfully
|
||||||
|
|||||||
@@ -1,209 +0,0 @@
|
|||||||
# How to use networking
|
|
||||||
|
|
||||||
cloud-hypervisor can emulate one or more virtual network interfaces, represented at the hypervisor host by [tap devices](https://www.kernel.org/doc/Documentation/networking/tuntap.txt). This guide briefly describes, in a manual and distribution neutral way, how to setup and use networking with cloud-hypervisor.
|
|
||||||
|
|
||||||
## Multiple queue support for net devices
|
|
||||||
|
|
||||||
While multiple vcpus defined for guest, to gain the benefit of vcpu scalable to improve performance, it suggests to define multiple queue pairs for net devices, one Tx/Rx queue pair per one vcpu, that means the number of queue pairs at least is equal to the vcpu count. In that case, after virtnet driver set cpu affinity for virtqueues in guest kernel, vcpus could handle interrupt from different virtqueue pairs in parallel.
|
|
||||||
|
|
||||||
It will gain better performance for guest that has multiple queues defined for net devices while it has multiple net sessions running in userspace.
|
|
||||||
|
|
||||||
To enable multiple queue support in cloud-hypervisor, multiple queue pairs will be defined, while multiple tap fds will be opened for the same tap device, it will also have multiple threads started, each thread will monitor and handle the events from each virtqueue pairs and the associated tap fd.
|
|
||||||
|
|
||||||
Note:
|
|
||||||
|
|
||||||
- Currently, it does not support to use ethtool to change the combined queue numbers in guest.
|
|
||||||
- Multiple queue is enabled for vhost-user-net backend in cloud-hypervisor, however, multiple thread is not added to handle mq, thus, the performance for vhost-user-net backend is not supposed to be improved. The multiple thread will be added for backend later.
|
|
||||||
- Performance test for vhost-user-net will be covered once vhost-user-net backend has multiple thread supported.
|
|
||||||
- Performance test for virtio-net is done by comparing 2 queue pairs with 1 queue pairs, that to run 2 iperf3 sessions in the same test environments, throughput is improved about 37%.
|
|
||||||
|
|
||||||
## Start cloud-hypervisor with net devices
|
|
||||||
|
|
||||||
Use one `--net` command-line argument from cloud-hypervisor to specify the emulation of one or more virtual NIC's. The example below instructs cloud-hypervisor to emulate for instance 2 virtual NIC's:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./cloud-hypervisor \
|
|
||||||
--cpus boot=4 \
|
|
||||||
--memory "size=512M" \
|
|
||||||
--disk path=focal-server-cloudimg-amd64.raw \
|
|
||||||
--kernel my-vmlinux.bin \
|
|
||||||
--cmdline "console=ttyS0 console=hvc0 root=/dev/vda1 rw" \
|
|
||||||
--net tap=ich0,mac=a4:a1:c2:00:00:01,ip=192.168.4.2,mask=255.255.255.0,num_queues=2,queue_size=256 \
|
|
||||||
tap=ich1,mac=a4:a1:c2:00:00:02,ip=10.0.1.2,mask=255.255.255.0,num_queues=2,queue_size=256
|
|
||||||
```
|
|
||||||
|
|
||||||
The `--net` argument takes 1 or more space-separated strings of key value pairs containing the following 4 keys or fields:
|
|
||||||
|
|
||||||
| Name | Purpose | Optional |
|
|
||||||
| ---------- | ---------------------- | -------- |
|
|
||||||
| tap | tap device name | Yes |
|
|
||||||
| mac | vNIC mac address | Yes |
|
|
||||||
| ip | tap IP IP address | yes |
|
|
||||||
| mask | tap IP netmask | Yes |
|
|
||||||
| num_queues | the number of queues | yes |
|
|
||||||
| queue_size | the size of each queue | Yes |
|
|
||||||
|
|
||||||
num_queues is the total number of tx and rx queues, the default value is 2, and it could be increased by multiples of 2. Additionally, num_queues is suggested to be as 2 times of vcpu count. The default value for queue_size is 256.
|
|
||||||
|
|
||||||
If the tap device is pre-created on host before guest boot up. To use multiple queue support for net device in guest, the tap device should be opened like this from host.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
[root@localhost ~]# ip tuntap add name ich0 mode tap multi_queue
|
|
||||||
```
|
|
||||||
|
|
||||||
And the `--net` device should specify support for multiple queues. `num_queues` must be a multiple of 2 starting at least from 4 since multiple queues really means multiple queue pairs. We need at least 2 pairs for this configuration to be correct:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
--net tap=ich0,mac=a4:a1:c2:00:00:01,ip=192.168.4.2,mask=255.255.255.0,num_queues=4,queue_size=256
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configure the tap devices
|
|
||||||
|
|
||||||
After starting cloud-hypervisor as shown above, 2 tap devices with state down will become available at the host:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# ip link show ich0
|
|
||||||
78: ich0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
|
|
||||||
link/ether 72:54:12:ff:ce:6f brd ff:ff:ff:ff:ff:ff
|
|
||||||
root@host:~# ip link show ich1
|
|
||||||
79: ich1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
|
|
||||||
link/ether 06:7a:fc:1b:9a:67 brd ff:ff:ff:ff:ff:ff
|
|
||||||
```
|
|
||||||
|
|
||||||
Set the tap devices to up state:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# ip link set up ich0
|
|
||||||
root@host:~# ip link set up ich1
|
|
||||||
|
|
||||||
root@host:~# ip link show ich0
|
|
||||||
78: ich0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
|
|
||||||
link/ether 72:54:12:ff:ce:6f brd ff:ff:ff:ff:ff:ff
|
|
||||||
root@host:~# ip link show ich1
|
|
||||||
79: ich1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN mode DEFAULT group default qlen 1000
|
|
||||||
link/ether 06:7a:fc:1b:9a:67 brd ff:ff:ff:ff:ff:ff
|
|
||||||
```
|
|
||||||
|
|
||||||
## Connect tap devices
|
|
||||||
|
|
||||||
Different networking models can be used to provide external connectivity. In this example we will
|
|
||||||
use 2 linux bridges emulating 2 different networks. The integration bridge (ich-int) in this example will also be used
|
|
||||||
for external connectivity.
|
|
||||||
|
|
||||||
Create the bridges and connect the cloud-hypervisor tap devices to the bridges:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# brctl addbr ich-int
|
|
||||||
root@host:~# brctl addbr ich-dpl
|
|
||||||
root@host:~# ip link set up ich-int
|
|
||||||
root@host:~# ip link set up ich-dpl
|
|
||||||
root@host:~# brctl addif ich-int ich0
|
|
||||||
root@host:~# brctl addif ich-dpl ich1
|
|
||||||
root@host:~# brctl show
|
|
||||||
bridge name bridge id STP enabled interfaces
|
|
||||||
ich-dpl 8000.067afc1b9a67 no ich1
|
|
||||||
ich-int 8000.725412ffce6f no ich0
|
|
||||||
```
|
|
||||||
|
|
||||||
This completes the layer 2 wiring: The cloud-hypervisor is now connected to the hypervisor host via the 2 linux bridges.
|
|
||||||
|
|
||||||
## IP (Layer 3) provisioning
|
|
||||||
|
|
||||||
### Hypervisor host
|
|
||||||
|
|
||||||
On the hypervisor host add the network gateway IP address of each network to the 2 linux bridges:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# ip addr add 192.168.4.1/24 dev ich-int
|
|
||||||
root@host:~# ip addr add 10.0.1.1/24 dev ich-dpl
|
|
||||||
```
|
|
||||||
|
|
||||||
The routing table of the hypervisor host should now also have corresponding routing entries:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# route -n
|
|
||||||
Kernel IP routing table
|
|
||||||
Destination Gateway Genmask Flags Metric Ref Use Iface
|
|
||||||
0.0.0.0 192.168.178.1 0.0.0.0 UG 600 0 0 wlan1
|
|
||||||
10.0.1.0 0.0.0.0 255.255.255.0 U 0 0 0 ich-dpl
|
|
||||||
192.168.4.0 0.0.0.0 255.255.255.0 U 0 0 0 ich-int
|
|
||||||
192.168.178.0 0.0.0.0 255.255.255.0 U 600 0 0 wlan1
|
|
||||||
```
|
|
||||||
|
|
||||||
### Virtual Machine
|
|
||||||
|
|
||||||
Within the virtual machine set the vNIC's to up state and provision the corresponding IP addresses on the 2 vNIC's. The steps outlined below use the ip command as an example. Alternative distribution specific procedures can also apply.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@guest:~# ip link set up enp0s2
|
|
||||||
root@guest:~# ip link set up enp0s3
|
|
||||||
root@guest:~# ip addr add 192.168.4.2/24 dev enp0s2
|
|
||||||
root@guest:~# ip addr add 10.0.1.2/24 dev enp0s3
|
|
||||||
```
|
|
||||||
|
|
||||||
IP connectivity between the virtual machine and the hypervisor-host can be verified by sending
|
|
||||||
ICMP requests to the hypervisor-host for the gateway IP address from within the virtual machine:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@guest:~# ping 192.168.4.1
|
|
||||||
PING 192.168.4.1 (192.168.4.1) 56(84) bytes of data.
|
|
||||||
64 bytes from 192.168.4.1: icmp_seq=1 ttl=64 time=0.456 ms
|
|
||||||
64 bytes from 192.168.4.1: icmp_seq=2 ttl=64 time=0.226 ms
|
|
||||||
root@guest:~# ping 10.0.1.1
|
|
||||||
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
|
|
||||||
64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=0.449 ms
|
|
||||||
64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=0.393 ms
|
|
||||||
```
|
|
||||||
|
|
||||||
The connection can now be used for instance to log into the virtual machine with
|
|
||||||
ssh under the precondition that the machine has an ssh daemon provisioned:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@host:~# ssh root@192.168.4.2
|
|
||||||
The authenticity of host '192.168.4.2 (192.168.4.2)' can't be established.
|
|
||||||
ECDSA key fingerprint is SHA256:qNAUmTtDMW9pNuZARkpLQhfw+Yc1tqUDBrQp7aZGSjw.
|
|
||||||
Are you sure you want to continue connecting (yes/no)? yes
|
|
||||||
Warning: Permanently added '192.168.4.2' (ECDSA) to the list of known hosts.
|
|
||||||
root@192.168.4.2's password:
|
|
||||||
Linux cloud-hypervisor 5.2.0 #2 SMP Thu Jul 11 08:08:16 CEST 2019 x86_64
|
|
||||||
|
|
||||||
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
|
|
||||||
permitted by applicable law.
|
|
||||||
|
|
||||||
|
|
||||||
Last login: Fri Jul 12 13:27:56 2019 from 192.168.4.1
|
|
||||||
root@guest:~#
|
|
||||||
```
|
|
||||||
|
|
||||||
## Internet connectivity
|
|
||||||
|
|
||||||
To enable internet connectivity a default gw and a nameserver has to be set within
|
|
||||||
the virtual machine:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@guest:~# ip route add default via 192.168.4.1
|
|
||||||
root@guest:~# cat /etc/resolv.conf
|
|
||||||
options timeout:2
|
|
||||||
domain vallis.nl
|
|
||||||
search vallis.nl
|
|
||||||
nameserver 192.168.178.1
|
|
||||||
```
|
|
||||||
|
|
||||||
make sure that the default gateway of the hypervisor host (in this example host 192.168.178.1 which is an adsl router) has an entry in the routing table for the 192.168.4.0/24 network otherwise IP connectivity will not work.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root@guest:~# nslookup ftp.nl.debian.org
|
|
||||||
Server: 192.168.178.1
|
|
||||||
Address: 192.168.178.1#53
|
|
||||||
|
|
||||||
Non-authoritative answer:
|
|
||||||
cdn-fastly.deb.debian.org canonical name = prod.debian.map.fastly.net.
|
|
||||||
Name: prod.debian.map.fastly.net
|
|
||||||
Address: 151.101.36.204
|
|
||||||
|
|
||||||
root@guest:~# apt-get update
|
|
||||||
Ign:1 http://cdn-fastly.deb.debian.org/debian stretch InRelease
|
|
||||||
Get:2 http://cdn-fastly.deb.debian.org/debian stretch Release [118 kB]
|
|
||||||
Get:3 http://cdn-fastly.deb.debian.org/debian stretch Release.gpg [2434 B]
|
|
||||||
Fetched 120 kB in 1s (110 kB/s)
|
|
||||||
```
|
|
||||||
@@ -8,9 +8,6 @@ snapshot and creates the exact same virtual machine, restoring the previously
|
|||||||
saved states. The new virtual machine is restored in a paused state, as it was
|
saved states. The new virtual machine is restored in a paused state, as it was
|
||||||
before the snapshot was performed.
|
before the snapshot was performed.
|
||||||
|
|
||||||
This feature is important for the project as it establishes the first step
|
|
||||||
towards the support for live migration.
|
|
||||||
|
|
||||||
## Snapshot a Cloud Hypervisor VM
|
## Snapshot a Cloud Hypervisor VM
|
||||||
|
|
||||||
First thing, we must run a Cloud Hypervisor VM:
|
First thing, we must run a Cloud Hypervisor VM:
|
||||||
@@ -46,24 +43,22 @@ ll /home/foo/snapshot/
|
|||||||
total 4194536
|
total 4194536
|
||||||
drwxrwxr-x 2 foo bar 4096 Jul 22 11:50 ./
|
drwxrwxr-x 2 foo bar 4096 Jul 22 11:50 ./
|
||||||
drwxr-xr-x 47 foo bar 4096 Jul 22 11:47 ../
|
drwxr-xr-x 47 foo bar 4096 Jul 22 11:47 ../
|
||||||
-rw------- 1 foo bar 3221225472 Jul 22 11:19 memory-region-0
|
-rw------- 1 foo bar 1084 Jul 22 11:19 config.json
|
||||||
-rw------- 1 foo bar 1073741824 Jul 22 11:19 memory-region-1
|
-rw------- 1 foo bar 4294967296 Jul 22 11:19 memory-ranges
|
||||||
-rw------- 1 foo bar 217853 Jul 22 11:19 vm.json
|
-rw------- 1 foo bar 217853 Jul 22 11:19 state.json
|
||||||
```
|
```
|
||||||
|
|
||||||
In this particular example, we can observe that 2 memory region files were
|
`config.json` contains the virtual machine configuration. It is used to create
|
||||||
created. That is explained by the size of the guest RAM, which is 4GiB in this
|
a similar virtual machine with the correct amount of CPUs, RAM, and other
|
||||||
case. Because it exceeds 3GiB (which is where we can find a ~1GiB memory hole),
|
expected devices. It is stored in a human readable format so that it could be
|
||||||
Cloud Hypervisor needs 2 distinct memory regions to be created. Each memory
|
modified between the snapshot and restore phases to achieve some very special
|
||||||
region's content is stored through a dedicated file, which explains why we end
|
use cases. But for most cases, manually modifying the configuration should not
|
||||||
up with 2 different files, the first one containing the guest RAM range 0-3GiB
|
be needed.
|
||||||
and the second one containing the guest RAM range 3-4GiB.
|
|
||||||
|
|
||||||
`vm.json` gathers all information related to the virtual machine configuration
|
`memory-ranges` stores the content of the guest RAM.
|
||||||
and state. The configuration bits are used to create a similar virtual machine
|
|
||||||
with the correct amount of CPUs, RAM, and other expected devices. The state
|
`state.json` contains the virtual machine state. It is used to restore each
|
||||||
bits are used to restore each component in the state it was left before the
|
component in the state it was left before the snapshot occurred.
|
||||||
snapshot occurred.
|
|
||||||
|
|
||||||
## Restore a Cloud Hypervisor VM
|
## Restore a Cloud Hypervisor VM
|
||||||
|
|
||||||
@@ -100,13 +95,4 @@ snapshot earlier.
|
|||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
The support of snapshot/restore feature is still experimental, meaning one
|
VFIO devices and Intel SGX are out of scope.
|
||||||
might still find some bugs associated with it.
|
|
||||||
|
|
||||||
Additionally, some devices and features don't support to be snapshot and
|
|
||||||
restored yet:
|
|
||||||
- `vhost-user` devices
|
|
||||||
- `virtio-mem`
|
|
||||||
- Intel SGX
|
|
||||||
|
|
||||||
VFIO devices are out of scope.
|
|
||||||
|
|||||||
43
docs/uefi.md
43
docs/uefi.md
@@ -17,7 +17,7 @@ cd edk2
|
|||||||
. edksetup.sh
|
. edksetup.sh
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
|
|
||||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
echo "ACTIVE_PLATFORM=OvmfPkg/CloudHv/CloudHvX64.dsc" >> Conf/target.txt
|
||||||
echo "TARGET_ARCH=X64" >> Conf/target.txt
|
echo "TARGET_ARCH=X64" >> Conf/target.txt
|
||||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
||||||
|
|
||||||
@@ -25,52 +25,15 @@ make -C ./BaseTools
|
|||||||
build
|
build
|
||||||
```
|
```
|
||||||
|
|
||||||
After the successful build, the resulting firmware binaries are available under `Build/OvmfCh/DEBUG_GCC5/FV` underneath the edk2 checkout.
|
After the successful build, the resulting firmware binaries are available under `Build/CloudHvX64/DEBUG_GCC5/FV` underneath the edk2 checkout.
|
||||||
|
|
||||||
## Using OVMF Binaries
|
## Using OVMF Binaries
|
||||||
|
|
||||||
Any UEFI capable image can be booted using the Cloud Hypervisor specific firmware. Windows guests under Cloud Hypervisor only support UEFI boot, therefore OVMF is mandatory there.
|
Any UEFI capable image can be booted using the Cloud Hypervisor specific firmware. Windows guests under Cloud Hypervisor only support UEFI boot, therefore OVMF is mandatory there.
|
||||||
|
|
||||||
To make Cloud Hypervisor use UEFI boot, pass the `OVMF.fd` file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
|
To make Cloud Hypervisor use UEFI boot, pass the `CLOUDHV.fd` file path as an argument to the `--kernel` option. The firmware file will be opened in read only mode.
|
||||||
|
|
||||||
The same firmware can be used with Cloud Hypervisor or with QEMU. This is particularly useful if using QEMU for the preparation phase.
|
|
||||||
|
|
||||||
## Building UEFI Firmware with Compatibility Support Module (CSM)
|
|
||||||
|
|
||||||
CSM is a module that allows to boot legacy operating systems using the OVMF firmware. OVMF can embed a CSM build of SeaBIOS. To build the SeaBIOS with CSM support, add `CONFIG_CSM=y` to `.config` before the build. The outcome `out/Csm16.bin` is to be moved into `OvmfPkg/Csm/Csm16/Csm16.bin` before OVMF is built. Then, the OVMF build will have to be passed the `-D CSM_ENABLE` option in order to generate a legacy aware UEFI firmware. At the current stage, all the necessary patches are included in the Cloud Hypervisor specific [SeaBIOS branch](https://github.com/cloud-hypervisor/seabios/tree/ch). Taking into account the previous instructions, the modified command sequence to compile an OVMF binary with CSM support is the following one:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install uuid-dev nasm iasl build-essential python3-distutils git libncurses-dev
|
|
||||||
|
|
||||||
git clone https://github.com/cloud-hypervisor/seabios -b ch
|
|
||||||
cd seabios
|
|
||||||
make menuconfig
|
|
||||||
# Enable `CONFIG_CSM` and `CONFIG_QEMU_HARDWARE`
|
|
||||||
# Please make sure `python` is in your path
|
|
||||||
make CONFIG_CSM=y CONFIG_QEMU_HARDWARE=y
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
git clone https://github.com/cloud-hypervisor/edk2 -b ch
|
|
||||||
cd edk2
|
|
||||||
. edksetup.sh
|
|
||||||
git submodule update --init --recursive
|
|
||||||
cp ../seabios/out/Csm16.bin OvmfPkg/Csm/Csm16/
|
|
||||||
|
|
||||||
echo "ACTIVE_PLATFORM=OvmfPkg/OvmfCh.dsc" >> Conf/target.txt
|
|
||||||
echo "TARGET_ARCH=X64" >> Conf/target.txt
|
|
||||||
echo "TOOL_CHAIN_TAG=GCC5" >> Conf/target.txt
|
|
||||||
|
|
||||||
make -C ./BaseTools
|
|
||||||
build -DCSM_ENABLE
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note, that the CSM support has currently only been tested with Linux guests. There are no plans to provide legacy support for other OSes (e.g. Windows).
|
|
||||||
|
|
||||||
# Links
|
# Links
|
||||||
|
|
||||||
- [OVMF wiki](https://github.com/tianocore/tianocore.github.io/wiki/OVMF)
|
- [OVMF wiki](https://github.com/tianocore/tianocore.github.io/wiki/OVMF)
|
||||||
- [Cloud Hypervisor specific tree](https://github.com/cloud-hypervisor/edk2/tree/ch)
|
- [Cloud Hypervisor specific tree](https://github.com/cloud-hypervisor/edk2/tree/ch)
|
||||||
- [Redhat OVMF Status Report](https://access.redhat.com/sites/default/files/attachments/ovmf-whtepaper-031815.pdf)
|
|
||||||
- [SeaBIOS Build Overview](https://www.seabios.org/Build_overview#Build_as_a_UEFI_Compatibility_Support_Module_.28CSM.29)
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ iface eth0 inet dhcp
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# starting in the directory above rootfs
|
# starting in the directory above rootfs
|
||||||
sudo virtiofsd --socket-path=$PWD/virtiofs-rootfs.sock -o source=$PWD/rootfs -o cache=none &
|
sudo virtiofsd --socket-path=$PWD/virtiofs-rootfs.sock --shared-dir=$PWD/rootfs --cache=never &
|
||||||
sudo cloud-hypervisor \
|
sudo cloud-hypervisor \
|
||||||
--cpus boot=1,max=1 \
|
--cpus boot=1,max=1 \
|
||||||
--kernel vmlinux \
|
--kernel vmlinux \
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ __Prerequisites__
|
|||||||
- QEMU, version >=5.0.0 is recommended.
|
- QEMU, version >=5.0.0 is recommended.
|
||||||
- Windows installation ISO. Obtained through MSDN, Visual Studio subscription, evaluation center, etc.
|
- Windows installation ISO. Obtained through MSDN, Visual Studio subscription, evaluation center, etc.
|
||||||
- [VirtIO driver ISO](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/)
|
- [VirtIO driver ISO](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/)
|
||||||
- Suitable [OVMF](uefi.md) firmware
|
- Suitable firmware for Cloud Hypervisor (`CLOUDHV.fd`) and for QEMU (`OVMF.fd`)
|
||||||
- With the suggested image size of 30G, there should be enough free disk space to hold the installation ISO and any other necessary files
|
- With the suggested image size of 30G, there should be enough free disk space to hold the installation ISO and any other necessary files
|
||||||
|
|
||||||
This step currently requires QEMU to install Windows onto the guest. QEMU is only used at the preparation stage, the resulting image is then fully functional with Cloud Hypervisor.
|
This step currently requires QEMU to install Windows onto the guest. QEMU is only used at the preparation stage, the resulting image is then fully functional with Cloud Hypervisor.
|
||||||
@@ -67,7 +67,7 @@ The basic command to boot a Windows image. The configuration section should be c
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
cloud-hypervisor \
|
cloud-hypervisor \
|
||||||
--kernel ./$OVMF_DIR/OVMF.fd \
|
--kernel ./$OVMF_DIR/CLOUDHV.fd \
|
||||||
--disk path=./$IMG_FILE \
|
--disk path=./$IMG_FILE \
|
||||||
--cpus boot=1,kvm_hyperv=on \
|
--cpus boot=1,kvm_hyperv=on \
|
||||||
--memory size=4G \
|
--memory size=4G \
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
serde = { version = "1.0.130", features = ["rc"] }
|
serde = { version = "1.0.136", features = ["rc"] }
|
||||||
serde_derive = "1.0.130"
|
serde_derive = "1.0.136"
|
||||||
serde_json = "1.0.72"
|
serde_json = "1.0.79"
|
||||||
|
|||||||
274
fuzz/Cargo.lock
generated
274
fuzz/Cargo.lock
generated
@@ -9,20 +9,11 @@ dependencies = [
|
|||||||
"vm-memory",
|
"vm-memory",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ansi_term"
|
|
||||||
version = "0.12.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
|
||||||
dependencies = [
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.51"
|
version = "1.0.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
|
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "api_client"
|
name = "api_client"
|
||||||
@@ -33,9 +24,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arbitrary"
|
name = "arbitrary"
|
||||||
version = "1.0.3"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "510c76ecefdceada737ea728f4f9a84bd2e1ef29f1ba555e560940fe279954de"
|
checksum = "c38b6b6b79f671c25e1a3e785b7b82d7562ffc9cd3efdc98627e5668a2472490"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arc-swap"
|
name = "arc-swap"
|
||||||
@@ -77,6 +68,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bincode"
|
name = "bincode"
|
||||||
version = "1.3.3"
|
version = "1.3.3"
|
||||||
@@ -119,9 +116,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.72"
|
version = "1.0.73"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -131,23 +128,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.34.0"
|
version = "3.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
checksum = "ced1892c55c910c1219e98d6fc8d71f6bddba7905866ce740066d8bfea859312"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term",
|
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
|
"os_str_bytes",
|
||||||
"strsim",
|
"strsim",
|
||||||
"term_size",
|
"termcolor",
|
||||||
|
"terminal_size",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"unicode-width",
|
|
||||||
"vec_map",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cloud-hypervisor"
|
name = "cloud-hypervisor"
|
||||||
version = "19.0.0"
|
version = "21.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"api_client",
|
"api_client",
|
||||||
@@ -187,9 +185,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32c"
|
name = "crc32c"
|
||||||
version = "0.6.0"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "210cdf933e6a81212bfabf90cd8762f471b5922e5f6b709547673ad8e04b9448"
|
checksum = "ee6b9c9389584bcba988bd0836086789b7f87ad91892d6a83d5291dbb24524b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
@@ -247,10 +245,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
checksum = "b643857cf70949306b81d7e92cb9d47add673868edac9863c4a49c42feaf3f1e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "gdbstub"
|
||||||
version = "0.2.3"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
checksum = "9fa2ca5d6b045de372cef3991f873389b421b4cabcfbe52f7787fae8b8b37906"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"log",
|
||||||
|
"managed",
|
||||||
|
"num-traits",
|
||||||
|
"paste",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gdbstub_arch"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "51dc4b5718ac76d21e8605c0966dd32d80273b89b11e6cfef467b04e45934d37"
|
||||||
|
dependencies = [
|
||||||
|
"gdbstub",
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -258,10 +280,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hashbrown"
|
||||||
version = "0.1.19"
|
version = "0.11.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hermit-abi"
|
||||||
|
version = "0.1.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7a30908dbce072eca83216eab939d2290080e00ca71611b96a09e5cdce5f3fa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -287,14 +315,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iced-x86"
|
name = "iced-x86"
|
||||||
version = "1.15.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "46e977036f7f5139d580c7f19ad62df9cb8ebd8410bb569e73585226be80a86f"
|
checksum = "158f5204401d08f91d19176112146d75e99b3cf745092e268fa7be33e09adcec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-uring"
|
name = "io-uring"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -307,14 +345,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.8"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-bindings"
|
name = "kvm-bindings"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0#9c497710ba9968d8efe15dbae03991b16cf82e23"
|
source = "git+https://github.com/cloud-hypervisor/kvm-bindings?branch=ch-v0.5.0-tdx#52e56d0e8ef0f6ea32fc0492e6a175b73617a49f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@@ -324,8 +362,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "kvm-ioctls"
|
name = "kvm-ioctls"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/rust-vmm/kvm-ioctls?branch=main#1e03e29cdfbb0cb108a98de7a78045a5a517f18e"
|
||||||
checksum = "97422ba48d7ffb66fd4d18130f72ab66f9bbbf791fb7a87b9291cdcfec437593"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -340,9 +377,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.108"
|
version = "0.2.119"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
|
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libfuzzer-sys"
|
name = "libfuzzer-sys"
|
||||||
@@ -373,6 +410,18 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "managed"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "micro_http"
|
name = "micro_http"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -410,15 +459,39 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "num-traits"
|
||||||
version = "1.8.0"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
|
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option_parser"
|
name = "option_parser"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_str_bytes"
|
||||||
|
version = "6.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pci"
|
name = "pci"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -428,6 +501,8 @@ dependencies = [
|
|||||||
"hypervisor",
|
"hypervisor",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_derive",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"versionize",
|
"versionize",
|
||||||
"versionize_derive",
|
"versionize_derive",
|
||||||
@@ -443,9 +518,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.32"
|
version = "1.0.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43"
|
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
@@ -463,9 +538,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.10"
|
version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05"
|
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -492,18 +567,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.2.3"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.6"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568"
|
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seccompiler"
|
name = "seccompiler"
|
||||||
@@ -516,30 +591,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "0.9.0"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
|
||||||
dependencies = [
|
|
||||||
"semver-parser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.130"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913"
|
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.130"
|
version = "1.0.136"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b"
|
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -548,9 +614,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.72"
|
version = "1.0.79"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527"
|
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -559,9 +625,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.10"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
|
checksum = "647c97df271007dcea485bb74ffdb57f2e683f1306c854f468a0c244badabf2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -584,15 +650,15 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.82"
|
version = "1.0.86"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59"
|
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -600,10 +666,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "term_size"
|
name = "termcolor"
|
||||||
version = "0.3.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-util",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -611,12 +686,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"term_size",
|
"terminal_size",
|
||||||
"unicode-width",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -639,12 +713,6 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-xid"
|
name = "unicode-xid"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
@@ -660,12 +728,6 @@ dependencies = [
|
|||||||
"getrandom",
|
"getrandom",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "vec_map"
|
|
||||||
version = "0.8.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "versionize"
|
name = "versionize"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
@@ -695,9 +757,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-bindings"
|
name = "vfio-bindings"
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a21f546f2bda37f5a8cfb138c87f95b8e34d2d78d6a7a92ba3785f4e08604a7"
|
checksum = "43449b404c488f70507dca193debd4bea361fe8089869b947adc19720e464bce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
]
|
]
|
||||||
@@ -705,12 +767,14 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "vfio-ioctls"
|
name = "vfio-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/rust-vmm/vfio-ioctls?branch=main#8f7f2210ebe71660938b05b2ed7eec9253478bc5"
|
source = "git+https://github.com/rust-vmm/vfio?branch=main#4630612f2ff300e78b6d55be324fb5481aa84661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"kvm-bindings",
|
"kvm-bindings",
|
||||||
"kvm-ioctls",
|
"kvm-ioctls",
|
||||||
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"thiserror",
|
||||||
"vfio-bindings",
|
"vfio-bindings",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
"vmm-sys-util",
|
"vmm-sys-util",
|
||||||
@@ -748,9 +812,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vhost"
|
name = "vhost"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d23ddeb452fb4f837526c6298cc8a2f4948e5595b0328a3d61b5eebe51874d7"
|
checksum = "3b56bf8f178fc500fe14505fca8b00dec76fc38f2304f461c8d9d7547982311d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -801,6 +865,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "virtio-queue"
|
name = "virtio-queue"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/rust-vmm/vm-virtio?branch=main#bbb22d43558a76cc7cc9c262c4be870a9e682a86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"vm-memory",
|
"vm-memory",
|
||||||
@@ -837,9 +902,9 @@ source = "git+https://github.com/rust-vmm/vm-fdt?branch=main#720e48e435b791ec6cb
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vm-memory"
|
name = "vm-memory"
|
||||||
version = "0.6.0"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0a8ebcb86ca457f9d6e14cf97009f679952eba42f0113de5db596e514cd0e43b"
|
checksum = "339d4349c126fdcd87e034631d7274370cf19eb0e87b33166bcd956589fc72c5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arc-swap",
|
"arc-swap",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -884,6 +949,8 @@ dependencies = [
|
|||||||
"devices",
|
"devices",
|
||||||
"epoll",
|
"epoll",
|
||||||
"event_monitor",
|
"event_monitor",
|
||||||
|
"gdbstub",
|
||||||
|
"gdbstub_arch",
|
||||||
"hypervisor",
|
"hypervisor",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -950,6 +1017,15 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-util"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-x86_64-pc-windows-gnu"
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
|||||||
@@ -10,22 +10,23 @@ cargo-fuzz = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
block_util = { path = "../block_util" }
|
block_util = { path = "../block_util" }
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
libfuzzer-sys = "0.4.2"
|
libfuzzer-sys = "0.4.2"
|
||||||
qcow = { path = "../qcow" }
|
qcow = { path = "../qcow" }
|
||||||
seccompiler = "0.2.0"
|
seccompiler = "0.2.0"
|
||||||
vhdx = { path = "../vhdx" }
|
vhdx = { path = "../vhdx" }
|
||||||
virtio-devices = { path = "../virtio-devices" }
|
virtio-devices = { path = "../virtio-devices" }
|
||||||
virtio-queue = { path = "../virtio-queue" }
|
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vm-memory = "0.6.0"
|
vm-memory = "0.7.0"
|
||||||
|
|
||||||
[dependencies.cloud-hypervisor]
|
[dependencies.cloud-hypervisor]
|
||||||
path = ".."
|
path = ".."
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"] }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx" }
|
||||||
|
kvm-ioctls = { git = "https://github.com/rust-vmm/kvm-ioctls", branch = "main" }
|
||||||
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
versionize_derive = { git = "https://github.com/cloud-hypervisor/versionize_derive", branch = "ch" }
|
||||||
|
|
||||||
# Prevent this from interfering with workspaces
|
# Prevent this from interfering with workspaces
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ fuzz_target!(|bytes| {
|
|||||||
|
|
||||||
let mut q = Queue::<
|
let mut q = Queue::<
|
||||||
GuestMemoryAtomic<GuestMemoryMmap>,
|
GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
QueueState<GuestMemoryAtomic<GuestMemoryMmap>>,
|
QueueState,
|
||||||
>::new(guest_memory.clone(), QUEUE_SIZE);
|
>::new(guest_memory.clone(), QUEUE_SIZE);
|
||||||
q.state.ready = true;
|
q.state.ready = true;
|
||||||
q.state.size = QUEUE_SIZE / 2;
|
q.state.size = QUEUE_SIZE / 2;
|
||||||
@@ -139,8 +139,7 @@ pub struct NoopVirtioInterrupt {}
|
|||||||
impl VirtioInterrupt for NoopVirtioInterrupt {
|
impl VirtioInterrupt for NoopVirtioInterrupt {
|
||||||
fn trigger(
|
fn trigger(
|
||||||
&self,
|
&self,
|
||||||
_int_type: &VirtioInterruptType,
|
_int_type: VirtioInterruptType,
|
||||||
_queue: Option<&Queue<GuestMemoryAtomic<GuestMemoryMmap>>>,
|
|
||||||
) -> std::result::Result<(), std::io::Error> {
|
) -> std::result::Result<(), std::io::Error> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,23 @@ mshv = ["mshv-ioctls", "mshv-bindings"]
|
|||||||
tdx = []
|
tdx = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
kvm-ioctls = { version = "0.11.0", optional = true }
|
kvm-ioctls = { version = "0.11.0", optional = true }
|
||||||
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0", features = ["with-serde", "fam-wrappers"], optional = true }
|
kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true }
|
||||||
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true}
|
||||||
serde = { version = "1.0.130", features = ["rc"] }
|
serde = { version = "1.0.136", features = ["rc"] }
|
||||||
serde_derive = "1.0.130"
|
serde_derive = "1.0.136"
|
||||||
serde_json = "1.0.72"
|
serde_json = "1.0.79"
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
vmm-sys-util = { version = "0.9.0", features = ["with-serde"] }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
[target.'cfg(target_arch = "x86_64")'.dependencies.iced-x86]
|
||||||
version = "1.15.0"
|
version = "1.17.0"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
features = ["std", "decoder", "op_code_info", "instr_info", "fast_fmt"]
|
||||||
|
|
||||||
|
|||||||
@@ -19,15 +19,19 @@ use crate::x86_64::{
|
|||||||
ExtendedControlRegisters, FpuState, MsrEntries, SpecialRegisters, StandardRegisters, VcpuEvents,
|
ExtendedControlRegisters, FpuState, MsrEntries, SpecialRegisters, StandardRegisters, VcpuEvents,
|
||||||
};
|
};
|
||||||
use crate::CpuState;
|
use crate::CpuState;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
use crate::DeviceAttr;
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
use crate::MpState;
|
use crate::MpState;
|
||||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
||||||
use crate::SuspendRegisters;
|
use crate::SuspendRegisters;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::Xsave;
|
use crate::Xsave;
|
||||||
#[cfg(feature = "mshv")]
|
#[cfg(feature = "tdx")]
|
||||||
use mshv_bindings::*;
|
use crate::{TdxExitDetails, TdxExitStatus};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
|
use vm_memory::GuestAddress;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
///
|
///
|
||||||
@@ -223,11 +227,27 @@ pub enum HypervisorCpuError {
|
|||||||
#[error("Failed to translate GVA: {0}")]
|
#[error("Failed to translate GVA: {0}")]
|
||||||
TranslateVirtualAddress(#[source] anyhow::Error),
|
TranslateVirtualAddress(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Set cpu attribute error
|
||||||
|
///
|
||||||
|
#[error("Failed to set vcpu attribute: {0}")]
|
||||||
|
SetVcpuAttribute(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
|
/// Check if cpu has a certain attribute error
|
||||||
|
///
|
||||||
|
#[error("Failed to check if vcpu has attribute: {0}")]
|
||||||
|
HasVcpuAttribute(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// Failed to initialize TDX on CPU
|
/// Failed to initialize TDX on CPU
|
||||||
///
|
///
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
#[error("Failed to initialize TDX: {0}")]
|
#[error("Failed to initialize TDX: {0}")]
|
||||||
InitializeTdx(#[source] std::io::Error),
|
InitializeTdx(#[source] std::io::Error),
|
||||||
|
///
|
||||||
|
/// Unknown TDX VM call
|
||||||
|
///
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
#[error("Unknown TDX VM call")]
|
||||||
|
UnknownTdxVmCall,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -244,6 +264,10 @@ pub enum VmExit<'a> {
|
|||||||
Reset,
|
Reset,
|
||||||
Shutdown,
|
Shutdown,
|
||||||
Hyperv,
|
Hyperv,
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
Tdx,
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
Debug,
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -259,7 +283,16 @@ pub trait Vcpu: Send + Sync {
|
|||||||
/// Returns the vCPU general purpose registers.
|
/// Returns the vCPU general purpose registers.
|
||||||
///
|
///
|
||||||
fn get_regs(&self) -> Result<StandardRegisters>;
|
fn get_regs(&self) -> Result<StandardRegisters>;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Sets vcpu attribute
|
||||||
|
///
|
||||||
|
fn set_vcpu_attr(&self, attr: &DeviceAttr) -> Result<()>;
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Check if vcpu has attribute.
|
||||||
|
///
|
||||||
|
fn has_vcpu_attr(&self, attr: &DeviceAttr) -> Result<()>;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Sets the vCPU general purpose registers.
|
/// Sets the vCPU general purpose registers.
|
||||||
@@ -368,6 +401,11 @@ pub trait Vcpu: Send + Sync {
|
|||||||
/// potential soft lockups when being resumed.
|
/// potential soft lockups when being resumed.
|
||||||
///
|
///
|
||||||
fn notify_guest_clock_paused(&self) -> Result<()>;
|
fn notify_guest_clock_paused(&self) -> Result<()>;
|
||||||
|
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||||
|
///
|
||||||
|
/// Sets debug registers to set hardware breakpoints and/or enable single step.
|
||||||
|
///
|
||||||
|
fn set_guest_debug(&self, addrs: &[GuestAddress], singlestep: bool) -> Result<()>;
|
||||||
///
|
///
|
||||||
/// Sets the type of CPU to be exposed to the guest and optional features.
|
/// Sets the type of CPU to be exposed to the guest and optional features.
|
||||||
///
|
///
|
||||||
@@ -428,11 +466,11 @@ pub trait Vcpu: Send + Sync {
|
|||||||
/// Triggers the running of the current virtual CPU returning an exit reason.
|
/// Triggers the running of the current virtual CPU returning an exit reason.
|
||||||
///
|
///
|
||||||
fn run(&self) -> std::result::Result<VmExit, HypervisorCpuError>;
|
fn run(&self) -> std::result::Result<VmExit, HypervisorCpuError>;
|
||||||
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Translate guest virtual address to guest physical address
|
/// Translate guest virtual address to guest physical address
|
||||||
///
|
///
|
||||||
fn translate_gva(&self, gva: u64, flags: u64) -> Result<(u64, hv_translate_gva_result)>;
|
fn translate_gva(&self, gva: u64, flags: u64) -> Result<(u64, u32)>;
|
||||||
///
|
///
|
||||||
/// Initialize TDX support on the vCPU
|
/// Initialize TDX support on the vCPU
|
||||||
///
|
///
|
||||||
@@ -443,4 +481,19 @@ pub trait Vcpu: Send + Sync {
|
|||||||
/// Return suspend registers(explicit and intercept suspend registers)
|
/// Return suspend registers(explicit and intercept suspend registers)
|
||||||
///
|
///
|
||||||
fn get_suspend_regs(&self) -> Result<SuspendRegisters>;
|
fn get_suspend_regs(&self) -> Result<SuspendRegisters>;
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
///
|
||||||
|
/// Set the "immediate_exit" state
|
||||||
|
///
|
||||||
|
fn set_immediate_exit(&self, exit: bool);
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
///
|
||||||
|
/// Returns the details about TDX exit reason
|
||||||
|
///
|
||||||
|
fn get_tdx_exit_details(&mut self) -> Result<TdxExitDetails>;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
///
|
||||||
|
/// Set the status code for TDX exit
|
||||||
|
///
|
||||||
|
fn set_tdx_status(&mut self, status: TdxExitStatus);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ use std::result;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
use vm_memory::Address;
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
// x86_64 dependencies
|
// x86_64 dependencies
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
@@ -44,12 +42,11 @@ use crate::arch::x86::NUM_IOAPIC_PINS;
|
|||||||
use aarch64::{RegList, Register, StandardRegisters};
|
use aarch64::{RegList, Register, StandardRegisters};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use kvm_bindings::{
|
use kvm_bindings::{
|
||||||
kvm_enable_cap, kvm_msr_entry, MsrList, KVM_CAP_HYPERV_SYNIC, KVM_CAP_SPLIT_IRQCHIP,
|
kvm_enable_cap, kvm_guest_debug, kvm_msr_entry, MsrList, KVM_CAP_HYPERV_SYNIC,
|
||||||
|
KVM_CAP_SPLIT_IRQCHIP, KVM_GUESTDBG_ENABLE, KVM_GUESTDBG_SINGLESTEP, KVM_GUESTDBG_USE_HW_BP,
|
||||||
};
|
};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use x86_64::{
|
use x86_64::{check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters};
|
||||||
check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters, KVM_TSS_ADDRESS,
|
|
||||||
};
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::{
|
pub use x86_64::{
|
||||||
CpuId, CpuIdEntry, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState as CpuState,
|
CpuId, CpuIdEntry, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState as CpuState,
|
||||||
@@ -85,7 +82,7 @@ pub use {
|
|||||||
kvm_bindings::kvm_clock_data as ClockData, kvm_bindings::kvm_create_device as CreateDevice,
|
kvm_bindings::kvm_clock_data as ClockData, kvm_bindings::kvm_create_device as CreateDevice,
|
||||||
kvm_bindings::kvm_device_attr as DeviceAttr,
|
kvm_bindings::kvm_device_attr as DeviceAttr,
|
||||||
kvm_bindings::kvm_irq_routing_entry as IrqRoutingEntry, kvm_bindings::kvm_mp_state as MpState,
|
kvm_bindings::kvm_irq_routing_entry as IrqRoutingEntry, kvm_bindings::kvm_mp_state as MpState,
|
||||||
kvm_bindings::kvm_userspace_memory_region as MemoryRegion,
|
kvm_bindings::kvm_run, kvm_bindings::kvm_userspace_memory_region as MemoryRegion,
|
||||||
kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress,
|
kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress,
|
||||||
kvm_ioctls::VcpuExit,
|
kvm_ioctls::VcpuExit,
|
||||||
};
|
};
|
||||||
@@ -93,6 +90,17 @@ pub use {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
const KVM_CAP_SGX_ATTRIBUTE: u32 = 196;
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const KVM_EXIT_TDX: u32 = 35;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const TDG_VP_VMCALL_GET_QUOTE: u64 = 0x10002;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT: u64 = 0x10004;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const TDG_VP_VMCALL_SUCCESS: u64 = 0;
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
const TDG_VP_VMCALL_INVALID_OPERAND: u64 = 0x8000000000000000;
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
|
ioctl_iowr_nr!(KVM_MEMORY_ENCRYPT_OP, KVMIO, 0xba, std::os::raw::c_ulong);
|
||||||
|
|
||||||
@@ -107,6 +115,18 @@ enum TdxCommand {
|
|||||||
Finalize,
|
Finalize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
pub enum TdxExitDetails {
|
||||||
|
GetQuote,
|
||||||
|
SetupEventNotifyInterrupt,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
pub enum TdxExitStatus {
|
||||||
|
Success,
|
||||||
|
InvalidOperand,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct KvmVmState {}
|
pub struct KvmVmState {}
|
||||||
|
|
||||||
@@ -139,6 +159,15 @@ pub struct KvmVm {
|
|||||||
/// vm.set/get().unwrap()
|
/// vm.set/get().unwrap()
|
||||||
///
|
///
|
||||||
impl vm::Vm for KvmVm {
|
impl vm::Vm for KvmVm {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Sets the address of the one-page region in the VM's address space.
|
||||||
|
///
|
||||||
|
fn set_identity_map_address(&self, address: u64) -> vm::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.set_identity_map_address(address)
|
||||||
|
.map_err(|e| vm::HypervisorVmError::SetIdentityMapAddress(e.into()))
|
||||||
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Sets the address of the three-page region in the VM's address space.
|
/// Sets the address of the three-page region in the VM's address space.
|
||||||
@@ -353,10 +382,6 @@ impl vm::Vm for KvmVm {
|
|||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
fn enable_split_irq(&self) -> vm::Result<()> {
|
fn enable_split_irq(&self) -> vm::Result<()> {
|
||||||
// Set TSS
|
|
||||||
self.fd
|
|
||||||
.set_tss_address(KVM_TSS_ADDRESS.raw_value() as usize)
|
|
||||||
.map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
|
|
||||||
// Create split irqchip
|
// Create split irqchip
|
||||||
// Only the local APIC is emulated in kernel, both PICs and IOAPIC
|
// Only the local APIC is emulated in kernel, both PICs and IOAPIC
|
||||||
// are not.
|
// are not.
|
||||||
@@ -776,6 +801,27 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.set_regs(regs)
|
.set_regs(regs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Set attribute for vcpu.
|
||||||
|
///
|
||||||
|
fn set_vcpu_attr(&self, attr: &DeviceAttr) -> cpu::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.set_device_attr(attr)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::SetVcpuAttribute(e.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
///
|
||||||
|
/// Check if vcpu has a certain attribute.
|
||||||
|
///
|
||||||
|
fn has_vcpu_attr(&self, attr: &DeviceAttr) -> cpu::Result<()> {
|
||||||
|
self.fd
|
||||||
|
.has_device_attr(attr)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::HasVcpuAttribute(e.into()))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Returns the vCPU special registers.
|
/// Returns the vCPU special registers.
|
||||||
@@ -936,6 +982,24 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
.set_xcrs(xcrs)
|
.set_xcrs(xcrs)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
|
||||||
}
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Translates guest virtual address to guest physical address using the `KVM_TRANSLATE` ioctl.
|
||||||
|
///
|
||||||
|
fn translate_gva(&self, gva: u64, _flags: u64) -> cpu::Result<(u64, u32)> {
|
||||||
|
let tr = self
|
||||||
|
.fd
|
||||||
|
.translate_gva(gva)
|
||||||
|
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
|
||||||
|
// tr.valid is set if the GVA is mapped to valid GPA.
|
||||||
|
match tr.valid {
|
||||||
|
0 => Err(cpu::HypervisorCpuError::TranslateVirtualAddress(anyhow!(
|
||||||
|
"Invalid GVA: {:#x}",
|
||||||
|
gva
|
||||||
|
))),
|
||||||
|
_ => Ok((tr.physical_address, 0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
///
|
///
|
||||||
/// Triggers the running of the current virtual CPU returning an exit reason.
|
/// Triggers the running of the current virtual CPU returning an exit reason.
|
||||||
///
|
///
|
||||||
@@ -1008,6 +1072,9 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
Ok(cpu::VmExit::MmioWrite(addr, data))
|
Ok(cpu::VmExit::MmioWrite(addr, data))
|
||||||
}
|
}
|
||||||
VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv),
|
VcpuExit::Hyperv => Ok(cpu::VmExit::Hyperv),
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
VcpuExit::Unsupported(KVM_EXIT_TDX) => Ok(cpu::VmExit::Tdx),
|
||||||
|
VcpuExit::Debug(_) => Ok(cpu::VmExit::Debug),
|
||||||
|
|
||||||
r => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
r => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
|
||||||
"Unexpected exit reason on vcpu run: {:?}",
|
"Unexpected exit reason on vcpu run: {:?}",
|
||||||
@@ -1050,9 +1117,55 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
/// potential soft lockups when being resumed.
|
/// potential soft lockups when being resumed.
|
||||||
///
|
///
|
||||||
fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
|
fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
|
||||||
|
if let Err(e) = self.fd.kvmclock_ctrl() {
|
||||||
|
// Linux kernel returns -EINVAL if the PV clock isn't yet initialised
|
||||||
|
// which could be because we're still in firmware or the guest doesn't
|
||||||
|
// use KVM clock.
|
||||||
|
if e.errno() != libc::EINVAL {
|
||||||
|
return Err(cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Sets debug registers to set hardware breakpoints and/or enable single step.
|
||||||
|
///
|
||||||
|
fn set_guest_debug(
|
||||||
|
&self,
|
||||||
|
addrs: &[vm_memory::GuestAddress],
|
||||||
|
singlestep: bool,
|
||||||
|
) -> cpu::Result<()> {
|
||||||
|
if addrs.len() > 4 {
|
||||||
|
return Err(cpu::HypervisorCpuError::SetDebugRegs(anyhow!(
|
||||||
|
"Support 4 breakpoints at most but {} addresses are passed",
|
||||||
|
addrs.len()
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dbg = kvm_guest_debug {
|
||||||
|
control: KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW_BP,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
if singlestep {
|
||||||
|
dbg.control |= KVM_GUESTDBG_SINGLESTEP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set bits 9 and 10.
|
||||||
|
// bit 9: GE (global exact breakpoint enable) flag.
|
||||||
|
// bit 10: always 1.
|
||||||
|
dbg.arch.debugreg[7] = 0x0600;
|
||||||
|
|
||||||
|
for (i, addr) in addrs.iter().enumerate() {
|
||||||
|
dbg.arch.debugreg[i] = addr.0;
|
||||||
|
// Set global breakpoint enable flag
|
||||||
|
dbg.arch.debugreg[7] |= 2 << (i * 2);
|
||||||
|
}
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.kvmclock_ctrl()
|
.set_guest_debug(&dbg)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into()))
|
.map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))
|
||||||
}
|
}
|
||||||
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
||||||
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
|
||||||
@@ -1566,6 +1679,50 @@ impl cpu::Vcpu for KvmVcpu {
|
|||||||
tdx_command(&self.fd.as_raw_fd(), TdxCommand::InitVcpu, 0, hob_address)
|
tdx_command(&self.fd.as_raw_fd(), TdxCommand::InitVcpu, 0, hob_address)
|
||||||
.map_err(cpu::HypervisorCpuError::InitializeTdx)
|
.map_err(cpu::HypervisorCpuError::InitializeTdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the "immediate_exit" state
|
||||||
|
///
|
||||||
|
fn set_immediate_exit(&self, exit: bool) {
|
||||||
|
self.fd.set_kvm_immediate_exit(exit.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the details about TDX exit reason
|
||||||
|
///
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
fn get_tdx_exit_details(&mut self) -> cpu::Result<TdxExitDetails> {
|
||||||
|
let kvm_run = self.fd.get_kvm_run();
|
||||||
|
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
||||||
|
|
||||||
|
tdx_vmcall.status_code = TDG_VP_VMCALL_INVALID_OPERAND;
|
||||||
|
|
||||||
|
if tdx_vmcall.type_ != 0 {
|
||||||
|
return Err(cpu::HypervisorCpuError::UnknownTdxVmCall);
|
||||||
|
}
|
||||||
|
|
||||||
|
match tdx_vmcall.subfunction {
|
||||||
|
TDG_VP_VMCALL_GET_QUOTE => Ok(TdxExitDetails::GetQuote),
|
||||||
|
TDG_VP_VMCALL_SETUP_EVENT_NOTIFY_INTERRUPT => {
|
||||||
|
Ok(TdxExitDetails::SetupEventNotifyInterrupt)
|
||||||
|
}
|
||||||
|
_ => Err(cpu::HypervisorCpuError::UnknownTdxVmCall),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the status code for TDX exit
|
||||||
|
///
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
fn set_tdx_status(&mut self, status: TdxExitStatus) {
|
||||||
|
let kvm_run = self.fd.get_kvm_run();
|
||||||
|
let tdx_vmcall = unsafe { &mut kvm_run.__bindgen_anon_1.tdx.u.vmcall };
|
||||||
|
|
||||||
|
tdx_vmcall.status_code = match status {
|
||||||
|
TdxExitStatus::Success => TDG_VP_VMCALL_SUCCESS,
|
||||||
|
TdxExitStatus::InvalidOperand => TDG_VP_VMCALL_INVALID_OPERAND,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Device struct for KVM
|
/// Device struct for KVM
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
use crate::arch::x86::{msr_index, SegmentRegisterOps, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
|
||||||
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
use crate::kvm::{Cap, Kvm, KvmError, KvmResult};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use vm_memory::GuestAddress;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
/// Export generically-named wrappers of kvm-bindings for Unix-based platforms
|
||||||
@@ -92,8 +91,6 @@ impl SegmentRegisterOps for SegmentRegister {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const KVM_TSS_ADDRESS: GuestAddress = GuestAddress(0xfffb_d000);
|
|
||||||
|
|
||||||
pub fn boot_msr_entries() -> MsrEntries {
|
pub fn boot_msr_entries() -> MsrEntries {
|
||||||
MsrEntries::from_entries(&[
|
MsrEntries::from_entries(&[
|
||||||
msr!(msr_index::MSR_IA32_SYSENTER_CS),
|
msr!(msr_index::MSR_IA32_SYSENTER_CS),
|
||||||
@@ -127,6 +124,15 @@ pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
|
|||||||
if !kvm.check_extension(Cap::SplitIrqchip) {
|
if !kvm.check_extension(Cap::SplitIrqchip) {
|
||||||
return Err(KvmError::CapabilityMissing(Cap::SplitIrqchip));
|
return Err(KvmError::CapabilityMissing(Cap::SplitIrqchip));
|
||||||
}
|
}
|
||||||
|
if !kvm.check_extension(Cap::SetIdentityMapAddr) {
|
||||||
|
return Err(KvmError::CapabilityMissing(Cap::SetIdentityMapAddr));
|
||||||
|
}
|
||||||
|
if !kvm.check_extension(Cap::SetTssAddr) {
|
||||||
|
return Err(KvmError::CapabilityMissing(Cap::SetTssAddr));
|
||||||
|
}
|
||||||
|
if !kvm.check_extension(Cap::ImmediateExit) {
|
||||||
|
return Err(KvmError::CapabilityMissing(Cap::ImmediateExit));
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -345,11 +345,11 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
|
|
||||||
// SAFETY: access_info is valid, otherwise we won't be here
|
// SAFETY: access_info is valid, otherwise we won't be here
|
||||||
assert!(
|
assert!(
|
||||||
!(unsafe { access_info.__bindgen_anon_1.string_op() } == 1),
|
(unsafe { access_info.__bindgen_anon_1.string_op() } != 1),
|
||||||
"String IN/OUT not supported"
|
"String IN/OUT not supported"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!(unsafe { access_info.__bindgen_anon_1.rep_prefix() } == 1),
|
(unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1),
|
||||||
"Rep IN/OUT not supported"
|
"Rep IN/OUT not supported"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -561,13 +561,17 @@ impl cpu::Vcpu for MshvVcpu {
|
|||||||
///
|
///
|
||||||
/// Translate guest virtual address to guest physical address
|
/// Translate guest virtual address to guest physical address
|
||||||
///
|
///
|
||||||
fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, hv_translate_gva_result)> {
|
fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, u32)> {
|
||||||
let r = self
|
let r = self
|
||||||
.fd
|
.fd
|
||||||
.translate_gva(gva, flags)
|
.translate_gva(gva, flags)
|
||||||
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
|
.map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
|
||||||
|
|
||||||
Ok(r)
|
let gpa = r.0;
|
||||||
|
// SAFETY: r is valid, otherwise this function will have returned
|
||||||
|
let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
|
||||||
|
|
||||||
|
Ok((gpa, result_code))
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
@@ -626,15 +630,13 @@ impl<'a> MshvEmulatorContext<'a> {
|
|||||||
// TODO: More fine-grained control for the flags
|
// TODO: More fine-grained control for the flags
|
||||||
let flags = HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_WRITE;
|
let flags = HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_WRITE;
|
||||||
|
|
||||||
let r = self
|
let (gpa, result_code) = self
|
||||||
.vcpu
|
.vcpu
|
||||||
.translate_gva(gva, flags.into())
|
.translate_gva(gva, flags.into())
|
||||||
.map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?;
|
.map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?;
|
||||||
|
|
||||||
// SAFETY: r is valid, otherwise this function will have returned
|
|
||||||
let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
|
|
||||||
match result_code {
|
match result_code {
|
||||||
hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(r.0),
|
hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(gpa),
|
||||||
_ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
|
_ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -764,6 +766,13 @@ fn hv_state_init() -> Arc<RwLock<HvState>> {
|
|||||||
/// vm.set/get().unwrap()
|
/// vm.set/get().unwrap()
|
||||||
///
|
///
|
||||||
impl vm::Vm for MshvVm {
|
impl vm::Vm for MshvVm {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
///
|
||||||
|
/// Sets the address of the one-page region in the VM's address space.
|
||||||
|
///
|
||||||
|
fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
///
|
///
|
||||||
/// Sets the address of the three-page region in the VM's address space.
|
/// Sets the address of the three-page region in the VM's address space.
|
||||||
|
|||||||
@@ -58,6 +58,11 @@ pub enum HypervisorVmError {
|
|||||||
#[error("Failed to create Vcpu: {0}")]
|
#[error("Failed to create Vcpu: {0}")]
|
||||||
CreateVcpu(#[source] anyhow::Error),
|
CreateVcpu(#[source] anyhow::Error),
|
||||||
///
|
///
|
||||||
|
/// Identity map address error
|
||||||
|
///
|
||||||
|
#[error("Failed to set identity map address: {0}")]
|
||||||
|
SetIdentityMapAddress(#[source] anyhow::Error),
|
||||||
|
///
|
||||||
/// TSS address error
|
/// TSS address error
|
||||||
///
|
///
|
||||||
#[error("Failed to set TSS address: {0}")]
|
#[error("Failed to set TSS address: {0}")]
|
||||||
@@ -217,6 +222,9 @@ pub type Result<T> = std::result::Result<T, HypervisorVmError>;
|
|||||||
/// This crate provides a hypervisor-agnostic interfaces for Vm
|
/// This crate provides a hypervisor-agnostic interfaces for Vm
|
||||||
///
|
///
|
||||||
pub trait Vm: Send + Sync {
|
pub trait Vm: Send + Sync {
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
/// Sets the address of the one-page region in the VM's address space.
|
||||||
|
fn set_identity_map_address(&self, address: u64) -> Result<()>;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
/// Sets the address of the three-page region in the VM's address space.
|
/// Sets the address of the three-page region in the VM's address space.
|
||||||
fn set_tss_address(&self, offset: usize) -> Result<()>;
|
fn set_tss_address(&self, offset: usize) -> Result<()>;
|
||||||
|
|||||||
@@ -7,20 +7,20 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
getrandom = "0.2"
|
getrandom = "0.2"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
net_gen = { path = "../net_gen" }
|
net_gen = { path = "../net_gen" }
|
||||||
rate_limiter = { path = "../rate_limiter" }
|
rate_limiter = { path = "../rate_limiter" }
|
||||||
serde = "1.0.130"
|
serde = "1.0.136"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
virtio-bindings = "0.1.0"
|
virtio-bindings = "0.1.0"
|
||||||
virtio-queue = { path = "../virtio-queue" }
|
virtio-queue = { git = "https://github.com/rust-vmm/vm-virtio", branch = "main" }
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic", "backend-bitmap"] }
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
vm-virtio = { path = "../vm-virtio" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
pnet = "0.28.0"
|
pnet = "0.29.0"
|
||||||
serde_json = "1.0.72"
|
serde_json = "1.0.79"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
use crate::GuestMemoryMmap;
|
use crate::GuestMemoryMmap;
|
||||||
use crate::Tap;
|
use crate::Tap;
|
||||||
use libc::c_uint;
|
use libc::c_uint;
|
||||||
|
use std::sync::Arc;
|
||||||
use virtio_bindings::bindings::virtio_net::{
|
use virtio_bindings::bindings::virtio_net::{
|
||||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS, VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET, VIRTIO_NET_CTRL_MQ,
|
||||||
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN,
|
||||||
@@ -14,6 +15,7 @@ use virtio_bindings::bindings::virtio_net::{
|
|||||||
};
|
};
|
||||||
use virtio_queue::Queue;
|
use virtio_queue::Queue;
|
||||||
use vm_memory::{ByteValued, Bytes, GuestMemoryAtomic, GuestMemoryError};
|
use vm_memory::{ByteValued, Bytes, GuestMemoryAtomic, GuestMemoryError};
|
||||||
|
use vm_virtio::{AccessPlatform, Translatable};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@@ -57,6 +59,7 @@ impl CtrlQueue {
|
|||||||
pub fn process(
|
pub fn process(
|
||||||
&mut self,
|
&mut self,
|
||||||
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||||
|
access_platform: Option<&Arc<dyn AccessPlatform>>,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let mut used_desc_heads = Vec::new();
|
let mut used_desc_heads = Vec::new();
|
||||||
for mut desc_chain in queue.iter().map_err(Error::QueueIterator)? {
|
for mut desc_chain in queue.iter().map_err(Error::QueueIterator)? {
|
||||||
@@ -64,16 +67,25 @@ impl CtrlQueue {
|
|||||||
|
|
||||||
let ctrl_hdr: ControlHeader = desc_chain
|
let ctrl_hdr: ControlHeader = desc_chain
|
||||||
.memory()
|
.memory()
|
||||||
.read_obj(ctrl_desc.addr())
|
.read_obj(
|
||||||
|
ctrl_desc
|
||||||
|
.addr()
|
||||||
|
.translate(access_platform, ctrl_desc.len() as usize),
|
||||||
|
)
|
||||||
.map_err(Error::GuestMemory)?;
|
.map_err(Error::GuestMemory)?;
|
||||||
let data_desc = desc_chain.next().ok_or(Error::NoDataDescriptor)?;
|
let data_desc = desc_chain.next().ok_or(Error::NoDataDescriptor)?;
|
||||||
|
|
||||||
|
let data_desc_addr = data_desc
|
||||||
|
.addr()
|
||||||
|
.translate(access_platform, data_desc.len() as usize);
|
||||||
|
|
||||||
let status_desc = desc_chain.next().ok_or(Error::NoStatusDescriptor)?;
|
let status_desc = desc_chain.next().ok_or(Error::NoStatusDescriptor)?;
|
||||||
|
|
||||||
let ok = match u32::from(ctrl_hdr.class) {
|
let ok = match u32::from(ctrl_hdr.class) {
|
||||||
VIRTIO_NET_CTRL_MQ => {
|
VIRTIO_NET_CTRL_MQ => {
|
||||||
let queue_pairs = desc_chain
|
let queue_pairs = desc_chain
|
||||||
.memory()
|
.memory()
|
||||||
.read_obj::<u16>(data_desc.addr())
|
.read_obj::<u16>(data_desc_addr)
|
||||||
.map_err(Error::GuestMemory)?;
|
.map_err(Error::GuestMemory)?;
|
||||||
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
|
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET {
|
||||||
warn!("Unsupported command: {}", ctrl_hdr.cmd);
|
warn!("Unsupported command: {}", ctrl_hdr.cmd);
|
||||||
@@ -91,7 +103,7 @@ impl CtrlQueue {
|
|||||||
VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
|
VIRTIO_NET_CTRL_GUEST_OFFLOADS => {
|
||||||
let features = desc_chain
|
let features = desc_chain
|
||||||
.memory()
|
.memory()
|
||||||
.read_obj::<u64>(data_desc.addr())
|
.read_obj::<u64>(data_desc_addr)
|
||||||
.map_err(Error::GuestMemory)?;
|
.map_err(Error::GuestMemory)?;
|
||||||
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET {
|
if u32::from(ctrl_hdr.cmd) != VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET {
|
||||||
warn!("Unsupported command: {}", ctrl_hdr.cmd);
|
warn!("Unsupported command: {}", ctrl_hdr.cmd);
|
||||||
@@ -120,7 +132,9 @@ impl CtrlQueue {
|
|||||||
.memory()
|
.memory()
|
||||||
.write_obj(
|
.write_obj(
|
||||||
if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8,
|
if ok { VIRTIO_NET_OK } else { VIRTIO_NET_ERR } as u8,
|
||||||
status_desc.addr(),
|
status_desc
|
||||||
|
.addr()
|
||||||
|
.translate(access_platform, status_desc.len() as usize),
|
||||||
)
|
)
|
||||||
.map_err(Error::GuestMemory)?;
|
.map_err(Error::GuestMemory)?;
|
||||||
let len = ctrl_desc.len() + data_desc.len() + status_desc.len();
|
let len = ctrl_desc.len() + data_desc.len() + status_desc.len();
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_gen::sockaddr {
|
|||||||
unsafe { mem::transmute(addr_in) }
|
unsafe { mem::transmute(addr_in) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_socket() -> Result<net::UdpSocket> {
|
fn create_inet_socket() -> Result<net::UdpSocket> {
|
||||||
// This is safe since we check the return value.
|
// This is safe since we check the return value.
|
||||||
let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
|
let sock = unsafe { libc::socket(libc::AF_INET, libc::SOCK_DGRAM, 0) };
|
||||||
if sock < 0 {
|
if sock < 0 {
|
||||||
@@ -88,6 +88,17 @@ fn create_socket() -> Result<net::UdpSocket> {
|
|||||||
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
|
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_unix_socket() -> Result<net::UdpSocket> {
|
||||||
|
// This is safe since we check the return value.
|
||||||
|
let sock = unsafe { libc::socket(libc::AF_UNIX, libc::SOCK_DGRAM, 0) };
|
||||||
|
if sock < 0 {
|
||||||
|
return Err(Error::CreateSocket(IoError::last_os_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is safe; nothing else will use or hold onto the raw sock fd.
|
||||||
|
Ok(unsafe { net::UdpSocket::from_raw_fd(sock) })
|
||||||
|
}
|
||||||
|
|
||||||
fn vnet_hdr_len() -> usize {
|
fn vnet_hdr_len() -> usize {
|
||||||
std::mem::size_of::<virtio_net_hdr_v1>()
|
std::mem::size_of::<virtio_net_hdr_v1>()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use virtio_queue::Queue;
|
use virtio_queue::Queue;
|
||||||
use vm_memory::{Bytes, GuestMemory, GuestMemoryAtomic};
|
use vm_memory::{Bytes, GuestMemory, GuestMemoryAtomic};
|
||||||
|
use vm_virtio::{AccessPlatform, Translatable};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TxVirtio {
|
pub struct TxVirtio {
|
||||||
@@ -38,6 +39,7 @@ impl TxVirtio {
|
|||||||
tap: &mut Tap,
|
tap: &mut Tap,
|
||||||
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||||
rate_limiter: &mut Option<RateLimiter>,
|
rate_limiter: &mut Option<RateLimiter>,
|
||||||
|
access_platform: Option<&Arc<dyn AccessPlatform>>,
|
||||||
) -> Result<bool, NetQueuePairError> {
|
) -> Result<bool, NetQueuePairError> {
|
||||||
let mut retry_write = false;
|
let mut retry_write = false;
|
||||||
let mut rate_limit_reached = false;
|
let mut rate_limit_reached = false;
|
||||||
@@ -58,10 +60,11 @@ impl TxVirtio {
|
|||||||
|
|
||||||
let mut iovecs = Vec::new();
|
let mut iovecs = Vec::new();
|
||||||
while let Some(desc) = next_desc {
|
while let Some(desc) = next_desc {
|
||||||
|
let desc_addr = desc.addr().translate(access_platform, desc.len() as usize);
|
||||||
if !desc.is_write_only() && desc.len() > 0 {
|
if !desc.is_write_only() && desc.len() > 0 {
|
||||||
let buf = desc_chain
|
let buf = desc_chain
|
||||||
.memory()
|
.memory()
|
||||||
.get_slice(desc.addr(), desc.len() as usize)
|
.get_slice(desc_addr, desc.len() as usize)
|
||||||
.map_err(NetQueuePairError::GuestMemory)?
|
.map_err(NetQueuePairError::GuestMemory)?
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
let iovec = libc::iovec {
|
let iovec = libc::iovec {
|
||||||
@@ -69,6 +72,14 @@ impl TxVirtio {
|
|||||||
iov_len: desc.len() as libc::size_t,
|
iov_len: desc.len() as libc::size_t,
|
||||||
};
|
};
|
||||||
iovecs.push(iovec);
|
iovecs.push(iovec);
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Invalid descriptor chain: address = 0x{:x} length = {} write_only = {}",
|
||||||
|
desc_addr.0,
|
||||||
|
desc.len(),
|
||||||
|
desc.is_write_only()
|
||||||
|
);
|
||||||
|
return Err(NetQueuePairError::DescriptorChainInvalid);
|
||||||
}
|
}
|
||||||
next_desc = desc_chain.next();
|
next_desc = desc_chain.next();
|
||||||
}
|
}
|
||||||
@@ -153,6 +164,7 @@ impl RxVirtio {
|
|||||||
tap: &mut Tap,
|
tap: &mut Tap,
|
||||||
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||||
rate_limiter: &mut Option<RateLimiter>,
|
rate_limiter: &mut Option<RateLimiter>,
|
||||||
|
access_platform: Option<&Arc<dyn AccessPlatform>>,
|
||||||
) -> Result<bool, NetQueuePairError> {
|
) -> Result<bool, NetQueuePairError> {
|
||||||
let mut exhausted_descs = true;
|
let mut exhausted_descs = true;
|
||||||
let mut rate_limit_reached = false;
|
let mut rate_limit_reached = false;
|
||||||
@@ -173,15 +185,23 @@ impl RxVirtio {
|
|||||||
let desc = desc_chain
|
let desc = desc_chain
|
||||||
.next()
|
.next()
|
||||||
.ok_or(NetQueuePairError::DescriptorChainTooShort)?;
|
.ok_or(NetQueuePairError::DescriptorChainTooShort)?;
|
||||||
let num_buffers_addr = desc_chain.memory().checked_offset(desc.addr(), 10).unwrap();
|
|
||||||
|
let num_buffers_addr = desc_chain
|
||||||
|
.memory()
|
||||||
|
.checked_offset(
|
||||||
|
desc.addr().translate(access_platform, desc.len() as usize),
|
||||||
|
10,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let mut next_desc = Some(desc);
|
let mut next_desc = Some(desc);
|
||||||
|
|
||||||
let mut iovecs = Vec::new();
|
let mut iovecs = Vec::new();
|
||||||
while let Some(desc) = next_desc {
|
while let Some(desc) = next_desc {
|
||||||
|
let desc_addr = desc.addr().translate(access_platform, desc.len() as usize);
|
||||||
if desc.is_write_only() && desc.len() > 0 {
|
if desc.is_write_only() && desc.len() > 0 {
|
||||||
let buf = desc_chain
|
let buf = desc_chain
|
||||||
.memory()
|
.memory()
|
||||||
.get_slice(desc.addr(), desc.len() as usize)
|
.get_slice(desc_addr, desc.len() as usize)
|
||||||
.map_err(NetQueuePairError::GuestMemory)?
|
.map_err(NetQueuePairError::GuestMemory)?
|
||||||
.as_ptr();
|
.as_ptr();
|
||||||
let iovec = libc::iovec {
|
let iovec = libc::iovec {
|
||||||
@@ -189,6 +209,14 @@ impl RxVirtio {
|
|||||||
iov_len: desc.len() as libc::size_t,
|
iov_len: desc.len() as libc::size_t,
|
||||||
};
|
};
|
||||||
iovecs.push(iovec);
|
iovecs.push(iovec);
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"Invalid descriptor chain: address = 0x{:x} length = {} write_only = {}",
|
||||||
|
desc_addr.0,
|
||||||
|
desc.len(),
|
||||||
|
desc.is_write_only()
|
||||||
|
);
|
||||||
|
return Err(NetQueuePairError::DescriptorChainInvalid);
|
||||||
}
|
}
|
||||||
next_desc = desc_chain.next();
|
next_desc = desc_chain.next();
|
||||||
}
|
}
|
||||||
@@ -282,6 +310,8 @@ pub enum NetQueuePairError {
|
|||||||
QueueIteratorFailed(virtio_queue::Error),
|
QueueIteratorFailed(virtio_queue::Error),
|
||||||
/// Descriptor chain is too short
|
/// Descriptor chain is too short
|
||||||
DescriptorChainTooShort,
|
DescriptorChainTooShort,
|
||||||
|
/// Descriptor chain does not contain valid descriptors
|
||||||
|
DescriptorChainInvalid,
|
||||||
/// Failed to determine if queue needed notification
|
/// Failed to determine if queue needed notification
|
||||||
QueueNeedsNotification(virtio_queue::Error),
|
QueueNeedsNotification(virtio_queue::Error),
|
||||||
/// Failed to enable notification on the queue
|
/// Failed to enable notification on the queue
|
||||||
@@ -308,6 +338,7 @@ pub struct NetQueuePair {
|
|||||||
pub rx_desc_avail: bool,
|
pub rx_desc_avail: bool,
|
||||||
pub rx_rate_limiter: Option<RateLimiter>,
|
pub rx_rate_limiter: Option<RateLimiter>,
|
||||||
pub tx_rate_limiter: Option<RateLimiter>,
|
pub tx_rate_limiter: Option<RateLimiter>,
|
||||||
|
pub access_platform: Option<Arc<dyn AccessPlatform>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetQueuePair {
|
impl NetQueuePair {
|
||||||
@@ -315,9 +346,12 @@ impl NetQueuePair {
|
|||||||
&mut self,
|
&mut self,
|
||||||
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||||
) -> Result<bool, NetQueuePairError> {
|
) -> Result<bool, NetQueuePairError> {
|
||||||
let tx_tap_retry =
|
let tx_tap_retry = self.tx.process_desc_chain(
|
||||||
self.tx
|
&mut self.tap,
|
||||||
.process_desc_chain(&mut self.tap, queue, &mut self.tx_rate_limiter)?;
|
queue,
|
||||||
|
&mut self.tx_rate_limiter,
|
||||||
|
self.access_platform.as_ref(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// We got told to try again when writing to the tap. Wait for the TAP to be writable
|
// We got told to try again when writing to the tap. Wait for the TAP to be writable
|
||||||
if tx_tap_retry && !self.tx_tap_listening {
|
if tx_tap_retry && !self.tx_tap_listening {
|
||||||
@@ -360,10 +394,12 @@ impl NetQueuePair {
|
|||||||
&mut self,
|
&mut self,
|
||||||
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
queue: &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||||
) -> Result<bool, NetQueuePairError> {
|
) -> Result<bool, NetQueuePairError> {
|
||||||
self.rx_desc_avail =
|
self.rx_desc_avail = !self.rx.process_desc_chain(
|
||||||
!self
|
&mut self.tap,
|
||||||
.rx
|
queue,
|
||||||
.process_desc_chain(&mut self.tap, queue, &mut self.rx_rate_limiter)?;
|
&mut self.rx_rate_limiter,
|
||||||
|
self.access_platform.as_ref(),
|
||||||
|
)?;
|
||||||
let rate_limit_reached = self
|
let rate_limit_reached = self
|
||||||
.rx_rate_limiter
|
.rx_rate_limiter
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -5,7 +5,10 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
use super::{create_sockaddr, create_socket, vnet_hdr_len, Error as NetUtilError, MacAddr};
|
use super::{
|
||||||
|
create_inet_socket, create_sockaddr, create_unix_socket, vnet_hdr_len, Error as NetUtilError,
|
||||||
|
MacAddr,
|
||||||
|
};
|
||||||
use crate::mac::MAC_ADDR_LEN;
|
use crate::mac::MAC_ADDR_LEN;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Error as IoError, Read, Result as IoResult, Write};
|
use std::io::{Error as IoError, Read, Result as IoResult, Write};
|
||||||
@@ -196,7 +199,7 @@ impl Tap {
|
|||||||
|
|
||||||
/// Set the host-side IP address for the tap interface.
|
/// Set the host-side IP address for the tap interface.
|
||||||
pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
|
pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_inet_socket().map_err(Error::NetUtil)?;
|
||||||
let addr = create_sockaddr(ip_addr);
|
let addr = create_sockaddr(ip_addr);
|
||||||
|
|
||||||
let mut ifreq = self.get_ifreq();
|
let mut ifreq = self.get_ifreq();
|
||||||
@@ -204,7 +207,6 @@ impl Tap {
|
|||||||
ifreq.ifr_ifru.ifru_addr = addr;
|
ifreq.ifr_ifru.ifru_addr = addr;
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -225,12 +227,11 @@ impl Tap {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_unix_socket().map_err(Error::NetUtil)?;
|
||||||
|
|
||||||
let mut ifreq = self.get_ifreq();
|
let mut ifreq = self.get_ifreq();
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -245,7 +246,6 @@ impl Tap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -257,12 +257,11 @@ impl Tap {
|
|||||||
|
|
||||||
/// Get mac addr for tap interface.
|
/// Get mac addr for tap interface.
|
||||||
pub fn get_mac_addr(&self) -> Result<MacAddr> {
|
pub fn get_mac_addr(&self) -> Result<MacAddr> {
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_unix_socket().map_err(Error::NetUtil)?;
|
||||||
|
|
||||||
let ifreq = self.get_ifreq();
|
let ifreq = self.get_ifreq();
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -279,7 +278,7 @@ impl Tap {
|
|||||||
|
|
||||||
/// Set the netmask for the subnet that the tap interface will exist on.
|
/// Set the netmask for the subnet that the tap interface will exist on.
|
||||||
pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
|
pub fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()> {
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_inet_socket().map_err(Error::NetUtil)?;
|
||||||
let addr = create_sockaddr(netmask);
|
let addr = create_sockaddr(netmask);
|
||||||
|
|
||||||
let mut ifreq = self.get_ifreq();
|
let mut ifreq = self.get_ifreq();
|
||||||
@@ -287,7 +286,6 @@ impl Tap {
|
|||||||
ifreq.ifr_ifru.ifru_addr = addr;
|
ifreq.ifr_ifru.ifru_addr = addr;
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFNETMASK as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -300,7 +298,6 @@ impl Tap {
|
|||||||
/// Set the offload flags for the tap interface.
|
/// Set the offload flags for the tap interface.
|
||||||
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
|
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
|
||||||
// ioctl is safe. Called with a valid tap fd, and we check the return.
|
// ioctl is safe. Called with a valid tap fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) };
|
unsafe { ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -312,11 +309,10 @@ impl Tap {
|
|||||||
|
|
||||||
/// Enable the tap interface.
|
/// Enable the tap interface.
|
||||||
pub fn enable(&self) -> Result<()> {
|
pub fn enable(&self) -> Result<()> {
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_unix_socket().map_err(Error::NetUtil)?;
|
||||||
|
|
||||||
let mut ifreq = self.get_ifreq();
|
let mut ifreq = self.get_ifreq();
|
||||||
|
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -336,7 +332,6 @@ impl Tap {
|
|||||||
(net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
|
(net_gen::net_device_flags_IFF_UP | net_gen::net_device_flags_IFF_RUNNING) as i16;
|
||||||
|
|
||||||
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
// ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||||
#[allow(clippy::cast_lossless)]
|
|
||||||
let ret =
|
let ret =
|
||||||
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
|
unsafe { ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
|
|||||||
@@ -10,22 +10,24 @@ kvm = ["vfio-ioctls/kvm"]
|
|||||||
mshv = ["vfio-ioctls/mshv"]
|
mshv = ["vfio-ioctls/mshv"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
hypervisor = { path = "../hypervisor" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "main", default-features = false }
|
vfio-ioctls = { git = "https://github.com/rust-vmm/vfio", branch = "main", default-features = false }
|
||||||
vfio_user = { path = "../vfio_user" }
|
vfio_user = { path = "../vfio_user" }
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
serde = "1.0.136"
|
||||||
|
serde_derive = "1.0.136"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
versionize = "0.1.6"
|
versionize = "0.1.6"
|
||||||
versionize_derive = "0.1.4"
|
versionize_derive = "0.1.4"
|
||||||
vm-allocator = { path = "../vm-allocator" }
|
vm-allocator = { path = "../vm-allocator" }
|
||||||
vm-device = { path = "../vm-device" }
|
vm-device = { path = "../vm-device" }
|
||||||
vm-memory = "0.6.0"
|
vm-memory = "0.7.0"
|
||||||
vm-migration = { path = "../vm-migration" }
|
vm-migration = { path = "../vm-migration" }
|
||||||
|
|
||||||
[dependencies.vfio-bindings]
|
[dependencies.vfio-bindings]
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
features = ["fam-wrappers"]
|
features = ["fam-wrappers"]
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ const ROM_BAR_REG: usize = 12;
|
|||||||
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
|
const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
|
||||||
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
|
const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
|
||||||
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
|
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
|
||||||
|
const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000;
|
||||||
|
const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000;
|
||||||
const NUM_BAR_REGS: usize = 6;
|
const NUM_BAR_REGS: usize = 6;
|
||||||
const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
|
const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
|
||||||
const FIRST_CAPABILITY_OFFSET: usize = 0x40;
|
const FIRST_CAPABILITY_OFFSET: usize = 0x40;
|
||||||
@@ -714,8 +716,15 @@ impl PciConfiguration {
|
|||||||
}
|
}
|
||||||
self.last_capability = Some((cap_offset, total_len));
|
self.last_capability = Some((cap_offset, total_len));
|
||||||
|
|
||||||
if cap_data.id() == PciCapabilityId::MsiX {
|
match cap_data.id() {
|
||||||
self.msix_cap_reg_idx = Some(cap_offset / 4);
|
PciCapabilityId::MessageSignalledInterrupts => {
|
||||||
|
self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
|
||||||
|
}
|
||||||
|
PciCapabilityId::MsiX => {
|
||||||
|
self.msix_cap_reg_idx = Some(cap_offset / 4);
|
||||||
|
self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(cap_offset)
|
Ok(cap_offset)
|
||||||
@@ -740,6 +749,11 @@ impl PciConfiguration {
|
|||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_msg_ctl(LittleEndian::read_u16(data));
|
.set_msg_ctl(LittleEndian::read_u16(data));
|
||||||
|
} else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
|
||||||
|
msix_config
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -922,16 +936,19 @@ impl PciBarConfiguration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn set_register_index(mut self, reg_idx: usize) -> Self {
|
pub fn set_register_index(mut self, reg_idx: usize) -> Self {
|
||||||
self.reg_idx = reg_idx;
|
self.reg_idx = reg_idx;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn set_address(mut self, addr: u64) -> Self {
|
pub fn set_address(mut self, addr: u64) -> Self {
|
||||||
self.addr = addr;
|
self.addr = addr;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn set_size(mut self, size: u64) -> Self {
|
pub fn set_size(mut self, size: u64) -> Self {
|
||||||
self.size = size;
|
self.size = size;
|
||||||
self
|
self
|
||||||
@@ -941,6 +958,7 @@ impl PciBarConfiguration {
|
|||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
|
pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
|
||||||
self.region_type = region_type;
|
self.region_type = region_type;
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
use crate::configuration::{self, PciBarRegionType};
|
use crate::configuration::{self, PciBarRegionType};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::{self, Display};
|
use std::fmt::{self, Display};
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use std::{self, io, result};
|
use std::{self, io, result};
|
||||||
use vm_allocator::{AddressAllocator, SystemAllocator};
|
use vm_allocator::{AddressAllocator, SystemAllocator};
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
@@ -51,7 +51,7 @@ pub trait PciDevice: BusDevice {
|
|||||||
/// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples.
|
/// returns an address. Returns a Vec of (GuestAddress, GuestUsize) tuples.
|
||||||
fn allocate_bars(
|
fn allocate_bars(
|
||||||
&mut self,
|
&mut self,
|
||||||
_allocator: &mut SystemAllocator,
|
_allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
_mmio_allocator: &mut AddressAllocator,
|
_mmio_allocator: &mut AddressAllocator,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
|
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
|||||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||||
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
||||||
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
||||||
use std::fmt::Display;
|
use serde::de::Visitor;
|
||||||
|
use std::fmt::{self, Display};
|
||||||
|
use std::num::ParseIntError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
/// PCI has four interrupt pins A->D.
|
/// PCI has four interrupt pins A->D.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@@ -52,6 +55,41 @@ pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
|
|||||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||||
pub struct PciBdf(u32);
|
pub struct PciBdf(u32);
|
||||||
|
|
||||||
|
struct PciBdfVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for PciBdfVisitor {
|
||||||
|
type Value = PciBdf;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("struct PciBdf")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for PciBdf {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(PciBdfVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serde::Serialize for PciBdf {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.collect_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PciBdf {
|
impl PciBdf {
|
||||||
pub fn segment(&self) -> u16 {
|
pub fn segment(&self) -> u16 {
|
||||||
((self.0 >> 16) & 0xffff) as u16
|
((self.0 >> 16) & 0xffff) as u16
|
||||||
@@ -121,3 +159,25 @@ impl Display for PciBdf {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FromStr for PciBdf {
|
||||||
|
type Err = ParseIntError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let items: Vec<&str> = s.split('.').collect();
|
||||||
|
assert_eq!(items.len(), 2);
|
||||||
|
let function = u8::from_str_radix(items[1], 16)?;
|
||||||
|
let items: Vec<&str> = items[0].split(':').collect();
|
||||||
|
assert_eq!(items.len(), 3);
|
||||||
|
let segment = u16::from_str_radix(items[0], 16)?;
|
||||||
|
let bus = u8::from_str_radix(items[1], 16)?;
|
||||||
|
let device = u8::from_str_radix(items[2], 16)?;
|
||||||
|
Ok(PciBdf::new(segment, bus, device, function))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for PciBdf {
|
||||||
|
fn from(bdf: &str) -> Self {
|
||||||
|
Self::from_str(bdf).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ impl MsixConfig {
|
|||||||
// Update interrupt routing
|
// Update interrupt routing
|
||||||
if old_masked != self.masked || old_enabled != self.enabled {
|
if old_masked != self.masked || old_enabled != self.enabled {
|
||||||
if self.enabled && !self.masked {
|
if self.enabled && !self.masked {
|
||||||
|
debug!("MSI-X enabled for device 0x{:x}", self.devid);
|
||||||
for (idx, table_entry) in self.table_entries.iter().enumerate() {
|
for (idx, table_entry) in self.table_entries.iter().enumerate() {
|
||||||
let config = MsiIrqSourceConfig {
|
let config = MsiIrqSourceConfig {
|
||||||
high_addr: table_entry.msg_addr_hi,
|
high_addr: table_entry.msg_addr_hi,
|
||||||
@@ -187,6 +188,7 @@ impl MsixConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if old_enabled || !old_masked {
|
} else if old_enabled || !old_masked {
|
||||||
|
debug!("MSI-X disabled for device 0x{:x}", self.devid);
|
||||||
if let Err(e) = self.interrupt_source_group.disable() {
|
if let Err(e) = self.interrupt_source_group.disable() {
|
||||||
error!("Failed disabling irq_fd: {:?}", e);
|
error!("Failed disabling irq_fd: {:?}", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
msi_num_enabled_vectors, BarReprogrammingParams, MsiConfig, MsixCap, MsixConfig,
|
msi_num_enabled_vectors, BarReprogrammingParams, MsiConfig, MsixCap, MsixConfig,
|
||||||
PciBarConfiguration, PciBarRegionType, PciCapabilityId, PciClassCode, PciConfiguration,
|
PciBarConfiguration, PciBarRegionType, PciBdf, PciCapabilityId, PciClassCode, PciConfiguration,
|
||||||
PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
|
PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE,
|
||||||
};
|
};
|
||||||
use byteorder::{ByteOrder, LittleEndian};
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
@@ -15,7 +15,7 @@ use std::collections::BTreeMap;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::sync::{Arc, Barrier};
|
use std::sync::{Arc, Barrier, Mutex};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use vfio_bindings::bindings::vfio::*;
|
use vfio_bindings::bindings::vfio::*;
|
||||||
use vfio_ioctls::{VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap};
|
use vfio_ioctls::{VfioContainer, VfioDevice, VfioIrq, VfioRegionInfoCap};
|
||||||
@@ -360,7 +360,7 @@ pub(crate) struct VfioCommon {
|
|||||||
impl VfioCommon {
|
impl VfioCommon {
|
||||||
pub(crate) fn allocate_bars(
|
pub(crate) fn allocate_bars(
|
||||||
&mut self,
|
&mut self,
|
||||||
allocator: &mut SystemAllocator,
|
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
mmio_allocator: &mut AddressAllocator,
|
mmio_allocator: &mut AddressAllocator,
|
||||||
vfio_wrapper: &dyn Vfio,
|
vfio_wrapper: &dyn Vfio,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||||
@@ -411,25 +411,27 @@ impl VfioCommon {
|
|||||||
let mut lower = vfio_wrapper.read_config_dword(bar_offset);
|
let mut lower = vfio_wrapper.read_config_dword(bar_offset);
|
||||||
|
|
||||||
if io_bar {
|
if io_bar {
|
||||||
|
// Mask flag bits (lowest 2 for I/O bars)
|
||||||
|
lower &= !0b11;
|
||||||
|
|
||||||
|
// BAR is not enabled
|
||||||
|
if lower == 0 {
|
||||||
|
bar_id += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
{
|
{
|
||||||
// IO BAR
|
// IO BAR
|
||||||
region_type = PciBarRegionType::IoRegion;
|
region_type = PciBarRegionType::IoRegion;
|
||||||
|
|
||||||
// Mask flag bits (lowest 2 for I/O bars)
|
|
||||||
lower &= !0b11;
|
|
||||||
|
|
||||||
// BAR is not enabled
|
|
||||||
if lower == 0 {
|
|
||||||
bar_id += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invert bits and add 1 to calculate size
|
// Invert bits and add 1 to calculate size
|
||||||
region_size = (!lower + 1) as u64;
|
region_size = (!lower + 1) as u64;
|
||||||
|
|
||||||
// The address needs to be 4 bytes aligned.
|
// The address needs to be 4 bytes aligned.
|
||||||
bar_addr = allocator
|
bar_addr = allocator
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.allocate_io_addresses(None, region_size, Some(0x4))
|
.allocate_io_addresses(None, region_size, Some(0x4))
|
||||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
||||||
}
|
}
|
||||||
@@ -476,6 +478,8 @@ impl VfioCommon {
|
|||||||
|
|
||||||
// BAR allocation must be naturally aligned
|
// BAR allocation must be naturally aligned
|
||||||
bar_addr = allocator
|
bar_addr = allocator
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
.allocate_mmio_hole_addresses(None, region_size, Some(region_size))
|
.allocate_mmio_hole_addresses(None, region_size, Some(region_size))
|
||||||
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
|
||||||
}
|
}
|
||||||
@@ -553,6 +557,7 @@ impl VfioCommon {
|
|||||||
cap: u8,
|
cap: u8,
|
||||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
vfio_wrapper: &dyn Vfio,
|
vfio_wrapper: &dyn Vfio,
|
||||||
|
bdf: PciBdf,
|
||||||
) {
|
) {
|
||||||
let msg_ctl = vfio_wrapper.read_config_word((cap + 2).into());
|
let msg_ctl = vfio_wrapper.read_config_word((cap + 2).into());
|
||||||
|
|
||||||
@@ -573,7 +578,11 @@ impl VfioCommon {
|
|||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let msix_config = MsixConfig::new(msix_cap.table_size(), interrupt_source_group.clone(), 0);
|
let msix_config = MsixConfig::new(
|
||||||
|
msix_cap.table_size(),
|
||||||
|
interrupt_source_group.clone(),
|
||||||
|
bdf.into(),
|
||||||
|
);
|
||||||
|
|
||||||
self.interrupt.msix = Some(VfioMsix {
|
self.interrupt.msix = Some(VfioMsix {
|
||||||
bar: msix_config,
|
bar: msix_config,
|
||||||
@@ -611,6 +620,7 @@ impl VfioCommon {
|
|||||||
&mut self,
|
&mut self,
|
||||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
vfio_wrapper: &dyn Vfio,
|
vfio_wrapper: &dyn Vfio,
|
||||||
|
bdf: PciBdf,
|
||||||
) {
|
) {
|
||||||
let mut cap_next = vfio_wrapper.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
let mut cap_next = vfio_wrapper.read_config_byte(PCI_CONFIG_CAPABILITY_OFFSET);
|
||||||
|
|
||||||
@@ -632,7 +642,12 @@ impl VfioCommon {
|
|||||||
if irq_info.count > 0 {
|
if irq_info.count > 0 {
|
||||||
// Parse capability only if the VFIO device
|
// Parse capability only if the VFIO device
|
||||||
// supports MSI-X.
|
// supports MSI-X.
|
||||||
self.parse_msix_capabilities(cap_next, interrupt_manager, vfio_wrapper);
|
self.parse_msix_capabilities(
|
||||||
|
cap_next,
|
||||||
|
interrupt_manager,
|
||||||
|
vfio_wrapper,
|
||||||
|
bdf,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -964,6 +979,7 @@ impl VfioPciDevice {
|
|||||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||||
iommu_attached: bool,
|
iommu_attached: bool,
|
||||||
|
bdf: PciBdf,
|
||||||
) -> Result<Self, VfioPciError> {
|
) -> Result<Self, VfioPciError> {
|
||||||
let device = Arc::new(device);
|
let device = Arc::new(device);
|
||||||
device.reset();
|
device.reset();
|
||||||
@@ -993,7 +1009,7 @@ impl VfioPciDevice {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper);
|
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
|
||||||
common.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)?;
|
common.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)?;
|
||||||
|
|
||||||
let vfio_pci_device = VfioPciDevice {
|
let vfio_pci_device = VfioPciDevice {
|
||||||
@@ -1308,7 +1324,7 @@ const PCI_ROM_EXP_BAR_INDEX: usize = 12;
|
|||||||
impl PciDevice for VfioPciDevice {
|
impl PciDevice for VfioPciDevice {
|
||||||
fn allocate_bars(
|
fn allocate_bars(
|
||||||
&mut self,
|
&mut self,
|
||||||
allocator: &mut SystemAllocator,
|
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
mmio_allocator: &mut AddressAllocator,
|
mmio_allocator: &mut AddressAllocator,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||||
self.common
|
self.common
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
use crate::vfio::{Interrupt, Vfio, VfioCommon, VfioError};
|
||||||
use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
|
use crate::{BarReprogrammingParams, PciBarRegionType, VfioPciError};
|
||||||
use crate::{
|
use crate::{
|
||||||
PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
PciBdf, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, PciSubclass,
|
||||||
};
|
};
|
||||||
use hypervisor::HypervisorVmError;
|
use hypervisor::HypervisorVmError;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@@ -67,6 +67,7 @@ impl VfioUserPciDevice {
|
|||||||
client: Arc<Mutex<Client>>,
|
client: Arc<Mutex<Client>>,
|
||||||
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
msi_interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
|
||||||
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
|
||||||
|
bdf: PciBdf,
|
||||||
) -> Result<Self, VfioUserPciDeviceError> {
|
) -> Result<Self, VfioUserPciDeviceError> {
|
||||||
// This is used for the BAR and capabilities only
|
// This is used for the BAR and capabilities only
|
||||||
let configuration = PciConfiguration::new(
|
let configuration = PciConfiguration::new(
|
||||||
@@ -104,7 +105,7 @@ impl VfioUserPciDevice {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper);
|
common.parse_capabilities(msi_interrupt_manager, &vfio_wrapper, bdf);
|
||||||
common
|
common
|
||||||
.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
|
.initialize_legacy_interrupt(legacy_interrupt_group, &vfio_wrapper)
|
||||||
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
.map_err(VfioUserPciDeviceError::InitializeLegacyInterrupts)?;
|
||||||
@@ -326,17 +327,33 @@ impl Vfio for VfioUserClientWrapper {
|
|||||||
);
|
);
|
||||||
let fds: Vec<i32> = event_fds.iter().map(|e| e.as_raw_fd()).collect();
|
let fds: Vec<i32> = event_fds.iter().map(|e| e.as_raw_fd()).collect();
|
||||||
|
|
||||||
self.client
|
// Batch into blocks of 16 fds as sendmsg() has a size limit
|
||||||
.lock()
|
let mut sent_fds = 0;
|
||||||
.unwrap()
|
let num_fds = event_fds.len() as u32;
|
||||||
.set_irqs(
|
while sent_fds < num_fds {
|
||||||
irq_index,
|
let remaining_fds = num_fds - sent_fds;
|
||||||
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
|
let count = if remaining_fds > 16 {
|
||||||
0,
|
16
|
||||||
event_fds.len() as u32,
|
} else {
|
||||||
&fds,
|
remaining_fds
|
||||||
)
|
};
|
||||||
.map_err(VfioError::VfioUser)
|
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.set_irqs(
|
||||||
|
irq_index,
|
||||||
|
VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
|
||||||
|
sent_fds,
|
||||||
|
count,
|
||||||
|
&fds[sent_fds as usize..(sent_fds + count) as usize],
|
||||||
|
)
|
||||||
|
.map_err(VfioError::VfioUser)?;
|
||||||
|
|
||||||
|
sent_fds += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> {
|
fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> {
|
||||||
@@ -373,7 +390,7 @@ impl Vfio for VfioUserClientWrapper {
|
|||||||
impl PciDevice for VfioUserPciDevice {
|
impl PciDevice for VfioUserPciDevice {
|
||||||
fn allocate_bars(
|
fn allocate_bars(
|
||||||
&mut self,
|
&mut self,
|
||||||
allocator: &mut SystemAllocator,
|
allocator: &Arc<Mutex<SystemAllocator>>,
|
||||||
mmio_allocator: &mut AddressAllocator,
|
mmio_allocator: &mut AddressAllocator,
|
||||||
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
|
||||||
self.common
|
self.common
|
||||||
|
|||||||
19
performance-metrics/Cargo.toml
Normal file
19
performance-metrics/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "performance-metrics"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["The Cloud Hypervisor Authors"]
|
||||||
|
edition = "2018"
|
||||||
|
build = "build.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
clap = { version = "3.1.5", features = ["wrap_help","cargo"] }
|
||||||
|
dirs = "4.0.0"
|
||||||
|
serde = { version = "1.0.136", features = ["rc"] }
|
||||||
|
serde_derive = "1.0.136"
|
||||||
|
serde_json = "1.0.78"
|
||||||
|
test_infra = { path = "../test_infra" }
|
||||||
|
thiserror = "1.0.30"
|
||||||
|
wait-timeout = "0.2.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
clap = { version = "3.1.5", features = ["wrap_help"] }
|
||||||
26
performance-metrics/build.rs
Normal file
26
performance-metrics/build.rs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright © 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
#[macro_use(crate_version)]
|
||||||
|
extern crate clap;
|
||||||
|
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut git_human_readable = "v".to_owned() + crate_version!();
|
||||||
|
if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() {
|
||||||
|
if git_out.status.success() {
|
||||||
|
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
||||||
|
git_human_readable = git_out_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This println!() has a special behavior, as it will set the environment
|
||||||
|
// variable GIT_HUMAN_READABLE, so that it can be reused from the binary.
|
||||||
|
// Particularly, this is used from the main.rs to display the exact
|
||||||
|
// version information.
|
||||||
|
println!("cargo:rustc-env=GIT_HUMAN_READABLE={}", git_human_readable);
|
||||||
|
}
|
||||||
474
performance-metrics/src/main.rs
Normal file
474
performance-metrics/src/main.rs
Normal file
@@ -0,0 +1,474 @@
|
|||||||
|
// Copyright © 2022 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
// Custom harness to run performance tests
|
||||||
|
extern crate test_infra;
|
||||||
|
#[macro_use(crate_authors)]
|
||||||
|
extern crate clap;
|
||||||
|
|
||||||
|
mod performance_tests;
|
||||||
|
|
||||||
|
use clap::{Arg, Command as ClapCommand};
|
||||||
|
use performance_tests::*;
|
||||||
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
use std::{env, fmt, process::Command, sync::mpsc::channel, thread, time::Duration};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
enum Error {
|
||||||
|
#[error("Error: test timed-out")]
|
||||||
|
TestTimeout,
|
||||||
|
#[error("Error: test failed")]
|
||||||
|
TestFailed,
|
||||||
|
#[error("Error creating log file: {0}")]
|
||||||
|
ReportFileCreation(std::io::Error),
|
||||||
|
#[error("Error writing log file: {0}")]
|
||||||
|
ReportFileWrite(std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct PerformanceTestResult {
|
||||||
|
name: String,
|
||||||
|
mean: f64,
|
||||||
|
std_dev: f64,
|
||||||
|
max: f64,
|
||||||
|
min: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct MetricsReport {
|
||||||
|
pub git_human_readable: String,
|
||||||
|
pub git_revision: String,
|
||||||
|
pub git_commit_date: String,
|
||||||
|
pub date: String,
|
||||||
|
pub results: Vec<PerformanceTestResult>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for MetricsReport {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut git_human_readable = "".to_string();
|
||||||
|
if let Ok(git_out) = Command::new("git").args(&["describe", "--dirty"]).output() {
|
||||||
|
if git_out.status.success() {
|
||||||
|
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
||||||
|
git_human_readable = git_out_str.trim().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut git_revision = "".to_string();
|
||||||
|
if let Ok(git_out) = Command::new("git").args(&["rev-parse", "HEAD"]).output() {
|
||||||
|
if git_out.status.success() {
|
||||||
|
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
||||||
|
git_revision = git_out_str.trim().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut git_commit_date = "".to_string();
|
||||||
|
if let Ok(git_out) = Command::new("git")
|
||||||
|
.args(&["show", "-s", "--format=%cd"])
|
||||||
|
.output()
|
||||||
|
{
|
||||||
|
if git_out.status.success() {
|
||||||
|
if let Ok(git_out_str) = String::from_utf8(git_out.stdout) {
|
||||||
|
git_commit_date = git_out_str.trim().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MetricsReport {
|
||||||
|
git_human_readable,
|
||||||
|
git_revision,
|
||||||
|
git_commit_date,
|
||||||
|
date: date(),
|
||||||
|
results: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PerformanceTestControl {
|
||||||
|
test_timeout: u32,
|
||||||
|
test_iterations: u32,
|
||||||
|
num_queues: Option<u32>,
|
||||||
|
queue_size: Option<u32>,
|
||||||
|
net_rx: Option<bool>,
|
||||||
|
fio_ops: Option<FioOps>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PerformanceTestControl {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let mut output = format!(
|
||||||
|
"test_timeout = {}s, test_iterations = {}",
|
||||||
|
self.test_timeout, self.test_iterations
|
||||||
|
);
|
||||||
|
if let Some(o) = self.num_queues {
|
||||||
|
output = format!("{}, num_queues = {}", output, o);
|
||||||
|
}
|
||||||
|
if let Some(o) = self.queue_size {
|
||||||
|
output = format!("{}, queue_size = {}", output, o);
|
||||||
|
}
|
||||||
|
if let Some(o) = self.net_rx {
|
||||||
|
output = format!("{}, net_rx = {}", output, o);
|
||||||
|
}
|
||||||
|
if let Some(o) = &self.fio_ops {
|
||||||
|
output = format!("{}, fio_ops = {}", output, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, "{}", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerformanceTestControl {
|
||||||
|
const fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
test_timeout: 10,
|
||||||
|
test_iterations: 5,
|
||||||
|
num_queues: None,
|
||||||
|
queue_size: None,
|
||||||
|
net_rx: None,
|
||||||
|
fio_ops: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A performance test should finish within the a certain time-out and
|
||||||
|
/// return a performance metrics number (including the average number and
|
||||||
|
/// standard deviation)
|
||||||
|
struct PerformanceTest {
|
||||||
|
pub name: &'static str,
|
||||||
|
pub func_ptr: fn(&PerformanceTestControl) -> f64,
|
||||||
|
pub control: PerformanceTestControl,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PerformanceTest {
|
||||||
|
pub fn run(&self) -> PerformanceTestResult {
|
||||||
|
let mut metrics = Vec::new();
|
||||||
|
for _ in 0..self.control.test_iterations {
|
||||||
|
metrics.push((self.func_ptr)(&self.control));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mean = mean(&metrics).unwrap();
|
||||||
|
let std_dev = std_deviation(&metrics).unwrap();
|
||||||
|
let max = metrics.clone().into_iter().reduce(f64::max).unwrap();
|
||||||
|
let min = metrics.clone().into_iter().reduce(f64::min).unwrap();
|
||||||
|
|
||||||
|
PerformanceTestResult {
|
||||||
|
name: self.name.to_string(),
|
||||||
|
mean,
|
||||||
|
std_dev,
|
||||||
|
max,
|
||||||
|
min,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) -> u64 {
|
||||||
|
((self.control.test_timeout + 20) * self.control.test_iterations) as u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mean(data: &[f64]) -> Option<f64> {
|
||||||
|
let count = data.len();
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
Some(data.iter().sum::<f64>() / count as f64)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn std_deviation(data: &[f64]) -> Option<f64> {
|
||||||
|
let count = data.len();
|
||||||
|
|
||||||
|
if count > 0 {
|
||||||
|
let mean = mean(data).unwrap();
|
||||||
|
let variance = data
|
||||||
|
.iter()
|
||||||
|
.map(|value| {
|
||||||
|
let diff = mean - *value;
|
||||||
|
diff * diff
|
||||||
|
})
|
||||||
|
.sum::<f64>()
|
||||||
|
/ count as f64;
|
||||||
|
|
||||||
|
Some(variance.sqrt())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TEST_LIST: [PerformanceTest; 15] = [
|
||||||
|
PerformanceTest {
|
||||||
|
name: "boot_time_s",
|
||||||
|
func_ptr: performance_boot_time,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
test_timeout: 2,
|
||||||
|
test_iterations: 10,
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "boot_time_pmem_s",
|
||||||
|
func_ptr: performance_boot_time_pmem,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
test_timeout: 2,
|
||||||
|
test_iterations: 10,
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "virtio_net_latency_us",
|
||||||
|
func_ptr: performance_net_latency,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(256),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "virtio_net_throughput_single_queue_rx_bps",
|
||||||
|
func_ptr: performance_net_throughput,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(256),
|
||||||
|
net_rx: Some(true),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "virtio_net_throughput_single_queue_tx_bps",
|
||||||
|
func_ptr: performance_net_throughput,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(256),
|
||||||
|
net_rx: Some(false),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "virtio_net_throughput_multi_queue_rx_bps",
|
||||||
|
func_ptr: performance_net_throughput,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(4),
|
||||||
|
queue_size: Some(256),
|
||||||
|
net_rx: Some(true),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "virtio_net_throughput_multi_queue_tx_bps",
|
||||||
|
func_ptr: performance_net_throughput,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(4),
|
||||||
|
queue_size: Some(256),
|
||||||
|
net_rx: Some(false),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_read_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(1),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::Read),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_write_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(1),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::Write),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_random_read_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(1),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::RandomRead),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_random_write_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(1),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::RandomWrite),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_multi_queue_read_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::Read),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_multi_queue_write_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::Write),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_multi_queue_random_read_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::RandomRead),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PerformanceTest {
|
||||||
|
name: "block_multi_queue_random_write_Bps",
|
||||||
|
func_ptr: performance_block_io,
|
||||||
|
control: PerformanceTestControl {
|
||||||
|
num_queues: Some(2),
|
||||||
|
queue_size: Some(128),
|
||||||
|
fio_ops: Some(FioOps::RandomWrite),
|
||||||
|
..PerformanceTestControl::default()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
fn run_test_with_timetout(test: &'static PerformanceTest) -> Result<PerformanceTestResult, Error> {
|
||||||
|
let (sender, receiver) = channel::<Result<PerformanceTestResult, Error>>();
|
||||||
|
thread::spawn(move || {
|
||||||
|
println!("Test '{}' running .. ({})", test.name, test.control);
|
||||||
|
|
||||||
|
let output = match std::panic::catch_unwind(|| test.run()) {
|
||||||
|
Ok(test_result) => {
|
||||||
|
println!(
|
||||||
|
"Test '{}' .. ok: mean = {}, std_dev = {}",
|
||||||
|
test_result.name, test_result.mean, test_result.std_dev
|
||||||
|
);
|
||||||
|
Ok(test_result)
|
||||||
|
}
|
||||||
|
Err(_) => Err(Error::TestFailed),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = sender.send(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Todo: Need to cleanup/kill all hanging child processes
|
||||||
|
let test_timeout = test.calc_timeout();
|
||||||
|
receiver
|
||||||
|
.recv_timeout(Duration::from_secs(test_timeout))
|
||||||
|
.map_err(|_| {
|
||||||
|
eprintln!(
|
||||||
|
"[Error] Test '{}' time-out after {} seconds",
|
||||||
|
test.name, test_timeout
|
||||||
|
);
|
||||||
|
Error::TestTimeout
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
|
||||||
|
fn date() -> String {
|
||||||
|
let output = test_infra::exec_host_command_output("date");
|
||||||
|
String::from_utf8_lossy(&output.stdout).trim().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let cmd_arguments = ClapCommand::new("performance-metrics")
|
||||||
|
.version(env!("GIT_HUMAN_READABLE"))
|
||||||
|
.author(crate_authors!())
|
||||||
|
.about("Generate the performance metrics data for Cloud Hypervisor")
|
||||||
|
.arg(
|
||||||
|
Arg::new("test-filter")
|
||||||
|
.long("test-filter")
|
||||||
|
.help("Filter metrics tests to run based on provided keywords")
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.takes_value(true)
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("list-tests")
|
||||||
|
.long("list-tests")
|
||||||
|
.help("Print the list of availale metrics tests")
|
||||||
|
.multiple_occurrences(true)
|
||||||
|
.takes_value(false)
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("report-file")
|
||||||
|
.long("report-file")
|
||||||
|
.help("Report file. Standard error is used if not specified")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
if cmd_arguments.is_present("list-tests") {
|
||||||
|
println!("List of available metrics tests:\n");
|
||||||
|
for test in TEST_LIST.iter() {
|
||||||
|
println!("\"{}\" ({})", test.name, test.control);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let test_filter = match cmd_arguments.values_of("test-filter") {
|
||||||
|
Some(s) => s.collect(),
|
||||||
|
None => Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut report_file: Box<dyn std::io::Write + Send> =
|
||||||
|
if let Some(file) = cmd_arguments.value_of("report-file") {
|
||||||
|
Box::new(
|
||||||
|
std::fs::File::create(std::path::Path::new(file))
|
||||||
|
.map_err(Error::ReportFileCreation)
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Box::new(std::io::stderr())
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run performance tests sequentially and report results (in both readable/json format)
|
||||||
|
let mut metrics_report: MetricsReport = Default::default();
|
||||||
|
|
||||||
|
init_tests();
|
||||||
|
|
||||||
|
for test in TEST_LIST.iter() {
|
||||||
|
if test_filter.is_empty() || test_filter.iter().any(|&s| test.name.contains(s)) {
|
||||||
|
match run_test_with_timetout(test) {
|
||||||
|
Ok(r) => {
|
||||||
|
metrics_report.results.push(r);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Aborting test due to error: '{:?}'", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup_tests();
|
||||||
|
|
||||||
|
// Todo: Report/upload to the metrics database
|
||||||
|
report_file
|
||||||
|
.write(
|
||||||
|
serde_json::to_string_pretty(&metrics_report)
|
||||||
|
.unwrap()
|
||||||
|
.as_bytes(),
|
||||||
|
)
|
||||||
|
.map_err(Error::ReportFileWrite)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
834
performance-metrics/src/performance_tests.rs
Normal file
834
performance-metrics/src/performance_tests.rs
Normal file
@@ -0,0 +1,834 @@
|
|||||||
|
// Copyright © 2022 Intel Corporation
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
//
|
||||||
|
|
||||||
|
// Performance tests
|
||||||
|
|
||||||
|
use crate::{mean, PerformanceTestControl};
|
||||||
|
use serde_json::Value;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process::{Child, Command, Stdio};
|
||||||
|
use std::string::String;
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::{fmt, fs};
|
||||||
|
use test_infra::Error as InfraError;
|
||||||
|
use test_infra::*;
|
||||||
|
use wait_timeout::ChildExt;
|
||||||
|
|
||||||
|
pub const FOCAL_IMAGE_NAME: &str = "focal-server-cloudimg-amd64-custom-20210609-0.raw";
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum WaitTimeoutError {
|
||||||
|
Timedout,
|
||||||
|
ExitStatus,
|
||||||
|
General(std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Error {
|
||||||
|
BootTimeParse,
|
||||||
|
EthrLogFile(std::io::Error),
|
||||||
|
EthrLogParse,
|
||||||
|
FioOutputParse,
|
||||||
|
Iperf3Parse,
|
||||||
|
Infra(InfraError),
|
||||||
|
Spawn(std::io::Error),
|
||||||
|
Scp(SshCommandError),
|
||||||
|
WaitTimeout(WaitTimeoutError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<InfraError> for Error {
|
||||||
|
fn from(e: InfraError) -> Self {
|
||||||
|
Self::Infra(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BLK_IO_TEST_IMG: &str = "/var/tmp/ch-blk-io-test.img";
|
||||||
|
|
||||||
|
pub fn init_tests() {
|
||||||
|
// The test image can not be created on tmpfs (e.g. /tmp) filesystem,
|
||||||
|
// as tmpfs does not support O_DIRECT
|
||||||
|
assert!(exec_host_command_output(&format!(
|
||||||
|
"dd if=/dev/zero of={} bs=1M count=4096",
|
||||||
|
BLK_IO_TEST_IMG
|
||||||
|
))
|
||||||
|
.status
|
||||||
|
.success());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup_tests() {
|
||||||
|
fs::remove_file(BLK_IO_TEST_IMG)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to remove file '{}'.", BLK_IO_TEST_IMG));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance tests are expected to be executed sequentially, so we can
|
||||||
|
// start VM guests with the same IP while putting them on a different
|
||||||
|
// private network. The default constructor "Guest::new()" does not work
|
||||||
|
// well, as we can easily create more than 256 VMs from repeating various
|
||||||
|
// performance tests dozens times in a single run.
|
||||||
|
fn performance_test_new_guest(disk_config: Box<dyn DiskConfig>) -> Guest {
|
||||||
|
Guest::new_from_ip_range(disk_config, "172.19", 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const DIRECT_KERNEL_BOOT_CMDLINE: &str =
|
||||||
|
"root=/dev/vda1 console=hvc0 rw systemd.journald.forward_to_console=1";
|
||||||
|
|
||||||
|
// Creates the path for direct kernel boot and return the path.
|
||||||
|
// For x86_64, this function returns the vmlinux kernel path.
|
||||||
|
// For AArch64, this function returns the PE kernel path.
|
||||||
|
fn direct_kernel_boot_path() -> PathBuf {
|
||||||
|
let mut workload_path = dirs::home_dir().unwrap();
|
||||||
|
workload_path.push("workloads");
|
||||||
|
|
||||||
|
let mut kernel_path = workload_path;
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
kernel_path.push("vmlinux");
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
kernel_path.push("Image");
|
||||||
|
|
||||||
|
kernel_path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait the child process for a given timeout
|
||||||
|
fn child_wait_timeout(child: &mut Child, timeout: u64) -> Result<(), WaitTimeoutError> {
|
||||||
|
match child.wait_timeout(Duration::from_secs(timeout)) {
|
||||||
|
Err(e) => {
|
||||||
|
return Err(WaitTimeoutError::General(e));
|
||||||
|
}
|
||||||
|
Ok(s) => match s {
|
||||||
|
None => {
|
||||||
|
return Err(WaitTimeoutError::Timedout);
|
||||||
|
}
|
||||||
|
Some(s) => {
|
||||||
|
if !s.success() {
|
||||||
|
return Err(WaitTimeoutError::ExitStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_iperf3_output(output: &[u8], sender: bool) -> Result<f64, Error> {
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let s = String::from_utf8_lossy(output);
|
||||||
|
let v: Value = serde_json::from_str(&s).expect("'iperf3' parse error: invalid json output");
|
||||||
|
|
||||||
|
let bps: f64 = if sender {
|
||||||
|
v["end"]["sum_sent"]["bits_per_second"]
|
||||||
|
.as_f64()
|
||||||
|
.expect("'iperf3' parse error: missing entry 'end.sum_sent.bits_per_second'")
|
||||||
|
} else {
|
||||||
|
v["end"]["sum_received"]["bits_per_second"]
|
||||||
|
.as_f64()
|
||||||
|
.expect("'iperf3' parse error: missing entry 'end.sum_received.bits_per_second'")
|
||||||
|
};
|
||||||
|
|
||||||
|
bps
|
||||||
|
})
|
||||||
|
.map_err(|_| {
|
||||||
|
eprintln!(
|
||||||
|
"=============== iperf3 output ===============\n\n{}\n\n===========end============\n\n",
|
||||||
|
String::from_utf8_lossy(output)
|
||||||
|
);
|
||||||
|
Error::Iperf3Parse
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_virtio_net_throughput(
|
||||||
|
test_timeout: u32,
|
||||||
|
queue_pairs: u32,
|
||||||
|
guest: &Guest,
|
||||||
|
receive: bool,
|
||||||
|
) -> Result<f64, Error> {
|
||||||
|
let default_port = 5201;
|
||||||
|
|
||||||
|
// 1. start the iperf3 server on the guest
|
||||||
|
for n in 0..queue_pairs {
|
||||||
|
guest
|
||||||
|
.ssh_command(&format!("iperf3 -s -p {} -D", default_port + n))
|
||||||
|
.map_err(InfraError::SshCommand)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::sleep(Duration::new(1, 0));
|
||||||
|
|
||||||
|
// 2. start the iperf3 client on host to measure RX through-put
|
||||||
|
let mut clients = Vec::new();
|
||||||
|
for n in 0..queue_pairs {
|
||||||
|
let mut cmd = Command::new("iperf3");
|
||||||
|
cmd.args(&[
|
||||||
|
"-J", // Output in JSON format
|
||||||
|
"-c",
|
||||||
|
&guest.network.guest_ip,
|
||||||
|
"-p",
|
||||||
|
&format!("{}", default_port + n),
|
||||||
|
"-t",
|
||||||
|
&format!("{}", test_timeout),
|
||||||
|
]);
|
||||||
|
// For measuring the guest transmit throughput (as a sender),
|
||||||
|
// use reverse mode of the iperf3 client on the host
|
||||||
|
if !receive {
|
||||||
|
cmd.args(&["-R"]);
|
||||||
|
}
|
||||||
|
let client = cmd
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.map_err(Error::Spawn)?;
|
||||||
|
|
||||||
|
clients.push(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut err: Option<Error> = None;
|
||||||
|
let mut bps = Vec::new();
|
||||||
|
let mut failed = false;
|
||||||
|
for c in clients {
|
||||||
|
let mut c = c;
|
||||||
|
if let Err(e) = child_wait_timeout(&mut c, test_timeout as u64 + 5) {
|
||||||
|
err = Some(Error::WaitTimeout(e));
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !failed {
|
||||||
|
// Safe to unwrap as we know the child has terminated succesffully
|
||||||
|
let output = c.wait_with_output().unwrap();
|
||||||
|
bps.push(parse_iperf3_output(&output.stdout, receive)?);
|
||||||
|
} else {
|
||||||
|
let _ = c.kill();
|
||||||
|
let output = c.wait_with_output().unwrap();
|
||||||
|
println!(
|
||||||
|
"=============== Client output [Error] ===============\n\n{}\n\n===========end============\n\n",
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(e) = err {
|
||||||
|
Err(e)
|
||||||
|
} else {
|
||||||
|
Ok(bps.iter().sum())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn performance_net_throughput(control: &PerformanceTestControl) -> f64 {
|
||||||
|
let test_timeout = control.test_timeout;
|
||||||
|
let rx = control.net_rx.unwrap();
|
||||||
|
|
||||||
|
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
|
|
||||||
|
let num_queues = control.num_queues.unwrap();
|
||||||
|
let queue_size = control.queue_size.unwrap();
|
||||||
|
let net_params = format!(
|
||||||
|
"tap=,mac={},ip={},mask=255.255.255.0,num_queues={},queue_size={}",
|
||||||
|
guest.network.guest_mac, guest.network.host_ip, num_queues, queue_size,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut child = GuestCommand::new(&guest)
|
||||||
|
.args(&["--cpus", &format!("boot={}", num_queues)])
|
||||||
|
.args(&["--memory", "size=4G"])
|
||||||
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
|
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||||
|
.default_disks()
|
||||||
|
.args(&["--net", net_params.as_str()])
|
||||||
|
.capture_output()
|
||||||
|
.set_print_cmd(false)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
guest.wait_vm_boot(None).unwrap();
|
||||||
|
measure_virtio_net_throughput(test_timeout, num_queues / 2, &guest, rx).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
handle_child_output(Err(e), &output);
|
||||||
|
panic!("test failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ethr_latency_output(output: &[u8]) -> Result<Vec<f64>, Error> {
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let s = String::from_utf8_lossy(output);
|
||||||
|
let mut latency = Vec::new();
|
||||||
|
for l in s.lines() {
|
||||||
|
let v: Value = serde_json::from_str(l).expect("'ethr' parse error: invalid json line");
|
||||||
|
// Skip header/summary lines
|
||||||
|
if let Some(avg) = v["Avg"].as_str() {
|
||||||
|
// Assume the latency unit is always "us"
|
||||||
|
latency.push(
|
||||||
|
avg.split("us").collect::<Vec<&str>>()[0]
|
||||||
|
.parse::<f64>()
|
||||||
|
.expect("'ethr' parse error: invalid 'Avg' entry"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
!latency.is_empty(),
|
||||||
|
"'ethr' parse error: no valid latency data found"
|
||||||
|
);
|
||||||
|
|
||||||
|
latency
|
||||||
|
})
|
||||||
|
.map_err(|_| {
|
||||||
|
eprintln!(
|
||||||
|
"=============== ethr output ===============\n\n{}\n\n===========end============\n\n",
|
||||||
|
String::from_utf8_lossy(output)
|
||||||
|
);
|
||||||
|
Error::EthrLogParse
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_virtio_net_latency(guest: &Guest, test_timeout: u32) -> Result<Vec<f64>, Error> {
|
||||||
|
// copy the 'ethr' tool to the guest image
|
||||||
|
let ethr_path = "/usr/local/bin/ethr";
|
||||||
|
let ethr_remote_path = "/tmp/ethr";
|
||||||
|
scp_to_guest(
|
||||||
|
Path::new(ethr_path),
|
||||||
|
Path::new(ethr_remote_path),
|
||||||
|
&guest.network.guest_ip,
|
||||||
|
//DEFAULT_SSH_RETRIES,
|
||||||
|
1,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
.map_err(Error::Scp)?;
|
||||||
|
|
||||||
|
// Start the ethr server on the guest
|
||||||
|
guest
|
||||||
|
.ssh_command(&format!("{} -s &> /dev/null &", ethr_remote_path))
|
||||||
|
.map_err(InfraError::SshCommand)?;
|
||||||
|
|
||||||
|
thread::sleep(Duration::new(1, 0));
|
||||||
|
|
||||||
|
// Start the ethr client on the host
|
||||||
|
let log_file = guest
|
||||||
|
.tmp_dir
|
||||||
|
.as_path()
|
||||||
|
.join("ethr.client.log")
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
let mut c = Command::new(ethr_path)
|
||||||
|
.args(&[
|
||||||
|
"-c",
|
||||||
|
&guest.network.guest_ip,
|
||||||
|
"-t",
|
||||||
|
"l",
|
||||||
|
"-o",
|
||||||
|
&log_file, // file output is JSON format
|
||||||
|
"-d",
|
||||||
|
&format!("{}s", test_timeout),
|
||||||
|
])
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.map_err(Error::Spawn)?;
|
||||||
|
|
||||||
|
if let Err(e) = child_wait_timeout(&mut c, test_timeout as u64 + 5).map_err(Error::WaitTimeout)
|
||||||
|
{
|
||||||
|
let _ = c.kill();
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the ethr latency test output
|
||||||
|
let content = fs::read(log_file).map_err(Error::EthrLogFile)?;
|
||||||
|
parse_ethr_latency_output(&content)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn performance_net_latency(control: &PerformanceTestControl) -> f64 {
|
||||||
|
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
|
|
||||||
|
let num_queues = control.num_queues.unwrap();
|
||||||
|
let queue_size = control.queue_size.unwrap();
|
||||||
|
let net_params = format!(
|
||||||
|
"tap=,mac={},ip={},mask=255.255.255.0,num_queues={},queue_size={}",
|
||||||
|
guest.network.guest_mac, guest.network.host_ip, num_queues, queue_size,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut child = GuestCommand::new(&guest)
|
||||||
|
.args(&["--cpus", &format!("boot={}", num_queues)])
|
||||||
|
.args(&["--memory", "size=4G"])
|
||||||
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
|
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||||
|
.default_disks()
|
||||||
|
.args(&["--net", net_params.as_str()])
|
||||||
|
.capture_output()
|
||||||
|
.set_print_cmd(false)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
guest.wait_vm_boot(None).unwrap();
|
||||||
|
|
||||||
|
// 'ethr' tool will measure the latency multiple times with provided test time
|
||||||
|
let latency = measure_virtio_net_latency(&guest, control.test_timeout).unwrap();
|
||||||
|
mean(&latency).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
handle_child_output(Err(e), &output);
|
||||||
|
panic!("test failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_boot_time_output(output: &[u8]) -> Result<f64, Error> {
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let l: Vec<String> = String::from_utf8_lossy(output)
|
||||||
|
.lines()
|
||||||
|
.into_iter()
|
||||||
|
.filter(|l| l.contains("Debug I/O port: Kernel code"))
|
||||||
|
.map(|l| l.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
l.len(),
|
||||||
|
2,
|
||||||
|
"Expecting two matching lines for 'Debug I/O port: Kernel code'"
|
||||||
|
);
|
||||||
|
|
||||||
|
let time_stamp_kernel_start = {
|
||||||
|
let s = l[0].split("--").collect::<Vec<&str>>();
|
||||||
|
assert_eq!(
|
||||||
|
s.len(),
|
||||||
|
2,
|
||||||
|
"Expecting '--' for the matching line of 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sample output: "[Debug I/O port: Kernel code 0x40] 0.096537 seconds"
|
||||||
|
assert!(
|
||||||
|
s[1].contains("0x40"),
|
||||||
|
"Expecting kernel code '0x40' for 'linux_kernel_start' time stamp output"
|
||||||
|
);
|
||||||
|
let t = s[1].split_whitespace().collect::<Vec<&str>>();
|
||||||
|
assert_eq!(
|
||||||
|
t.len(),
|
||||||
|
8,
|
||||||
|
"Expecting exact '8' words from the 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
t[7].eq("seconds"),
|
||||||
|
"Expecting 'seconds' as the the last word of the 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
|
||||||
|
t[6].parse::<f64>().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let time_stamp_user_start = {
|
||||||
|
let s = l[1].split("--").collect::<Vec<&str>>();
|
||||||
|
assert_eq!(
|
||||||
|
s.len(),
|
||||||
|
2,
|
||||||
|
"Expecting '--' for the matching line of 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sample output: "Debug I/O port: Kernel code 0x41] 0.198980 seconds"
|
||||||
|
assert!(
|
||||||
|
s[1].contains("0x41"),
|
||||||
|
"Expecting kernel code '0x41' for 'linux_kernel_start' time stamp output"
|
||||||
|
);
|
||||||
|
let t = s[1].split_whitespace().collect::<Vec<&str>>();
|
||||||
|
assert_eq!(
|
||||||
|
t.len(),
|
||||||
|
8,
|
||||||
|
"Expecting exact '8' words from the 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
t[7].eq("seconds"),
|
||||||
|
"Expecting 'seconds' as the the last word of the 'Debug I/O port' output"
|
||||||
|
);
|
||||||
|
|
||||||
|
t[6].parse::<f64>().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
time_stamp_user_start - time_stamp_kernel_start
|
||||||
|
})
|
||||||
|
.map_err(|_| {
|
||||||
|
eprintln!(
|
||||||
|
"=============== boot-time output ===============\n\n{}\n\n===========end============\n\n",
|
||||||
|
String::from_utf8_lossy(output)
|
||||||
|
);
|
||||||
|
Error::BootTimeParse
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn measure_boot_time(cmd: &mut GuestCommand, test_timeout: u32) -> Result<f64, Error> {
|
||||||
|
let mut child = cmd.capture_output().set_print_cmd(false).spawn().unwrap();
|
||||||
|
|
||||||
|
thread::sleep(Duration::new(test_timeout as u64, 0));
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
parse_boot_time_output(&output.stderr).map_err(|e| {
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start child stdout ====\n\n{}\n\n==== End child stdout ====",
|
||||||
|
String::from_utf8_lossy(&output.stdout)
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start child stderr ====\n\n{}\n\n==== End child stderr ====",
|
||||||
|
String::from_utf8_lossy(&output.stderr)
|
||||||
|
);
|
||||||
|
|
||||||
|
e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn performance_boot_time(control: &PerformanceTestControl) -> f64 {
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
|
let mut cmd = GuestCommand::new(&guest);
|
||||||
|
|
||||||
|
let c = cmd
|
||||||
|
.args(&["--memory", "size=1G"])
|
||||||
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
|
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||||
|
.args(&["--console", "off"])
|
||||||
|
.default_disks();
|
||||||
|
|
||||||
|
measure_boot_time(c, control.test_timeout).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_) => {
|
||||||
|
panic!("test failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn performance_boot_time_pmem(control: &PerformanceTestControl) -> f64 {
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
|
let mut cmd = GuestCommand::new(&guest);
|
||||||
|
let c = cmd
|
||||||
|
.args(&["--memory", "size=1G,hugepages=on"])
|
||||||
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
|
.args(&["--cmdline", "root=/dev/pmem0p1 console=ttyS0 quiet rw"])
|
||||||
|
.args(&["--console", "off"])
|
||||||
|
.args(&[
|
||||||
|
"--pmem",
|
||||||
|
format!(
|
||||||
|
"file={}",
|
||||||
|
guest.disk_config.disk(DiskType::OperatingSystem).unwrap()
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
measure_boot_time(c, control.test_timeout).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(_) => {
|
||||||
|
panic!("test failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FioOps {
|
||||||
|
Read,
|
||||||
|
RandomRead,
|
||||||
|
Write,
|
||||||
|
RandomWrite,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for FioOps {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
FioOps::Read => write!(f, "read"),
|
||||||
|
FioOps::RandomRead => write!(f, "randread"),
|
||||||
|
FioOps::Write => write!(f, "write"),
|
||||||
|
FioOps::RandomWrite => write!(f, "randwrite"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_fio_output(output: &str, fio_ops: &FioOps, num_jobs: u32) -> Result<f64, Error> {
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let v: Value =
|
||||||
|
serde_json::from_str(output).expect("'fio' parse error: invalid json output");
|
||||||
|
let jobs = v["jobs"]
|
||||||
|
.as_array()
|
||||||
|
.expect("'fio' parse error: missing entry 'jobs'");
|
||||||
|
assert_eq!(
|
||||||
|
jobs.len(),
|
||||||
|
num_jobs as usize,
|
||||||
|
"'fio' parse error: Unexpected number of 'fio' jobs."
|
||||||
|
);
|
||||||
|
|
||||||
|
let read = match fio_ops {
|
||||||
|
FioOps::Read | FioOps::RandomRead => true,
|
||||||
|
FioOps::Write | FioOps::RandomWrite => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut total_bps = 0_f64;
|
||||||
|
for j in jobs {
|
||||||
|
if read {
|
||||||
|
let bytes = j["read"]["io_bytes"]
|
||||||
|
.as_u64()
|
||||||
|
.expect("'fio' parse error: missing entry 'read.io_bytes'");
|
||||||
|
let runtime = j["read"]["runtime"]
|
||||||
|
.as_u64()
|
||||||
|
.expect("'fio' parse error: missing entry 'read.runtime'")
|
||||||
|
as f64
|
||||||
|
/ 1000_f64;
|
||||||
|
total_bps += bytes as f64 / runtime as f64;
|
||||||
|
} else {
|
||||||
|
let bytes = j["write"]["io_bytes"]
|
||||||
|
.as_u64()
|
||||||
|
.expect("'fio' parse error: missing entry 'write.io_bytes'");
|
||||||
|
let runtime = j["write"]["runtime"]
|
||||||
|
.as_u64()
|
||||||
|
.expect("'fio' parse error: missing entry 'write.runtime'")
|
||||||
|
as f64
|
||||||
|
/ 1000_f64;
|
||||||
|
total_bps += bytes as f64 / runtime as f64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
total_bps
|
||||||
|
})
|
||||||
|
.map_err(|_| {
|
||||||
|
eprintln!(
|
||||||
|
"=============== Fio output ===============\n\n{}\n\n===========end============\n\n",
|
||||||
|
output
|
||||||
|
);
|
||||||
|
Error::FioOutputParse
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn performance_block_io(control: &PerformanceTestControl) -> f64 {
|
||||||
|
let test_timeout = control.test_timeout;
|
||||||
|
let num_queues = control.num_queues.unwrap();
|
||||||
|
let queue_size = control.queue_size.unwrap();
|
||||||
|
let fio_ops = control.fio_ops.as_ref().unwrap();
|
||||||
|
|
||||||
|
let focal = UbuntuDiskConfig::new(FOCAL_IMAGE_NAME.to_string());
|
||||||
|
let guest = performance_test_new_guest(Box::new(focal));
|
||||||
|
let api_socket = guest
|
||||||
|
.tmp_dir
|
||||||
|
.as_path()
|
||||||
|
.join("cloud-hypervisor.sock")
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
let mut child = GuestCommand::new(&guest)
|
||||||
|
.args(&["--cpus", &format!("boot={}", num_queues)])
|
||||||
|
.args(&["--memory", "size=4G"])
|
||||||
|
.args(&["--kernel", direct_kernel_boot_path().to_str().unwrap()])
|
||||||
|
.args(&["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE])
|
||||||
|
.default_disks()
|
||||||
|
.default_net()
|
||||||
|
.args(&["--api-socket", &api_socket])
|
||||||
|
.capture_output()
|
||||||
|
.set_print_cmd(false)
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let r = std::panic::catch_unwind(|| {
|
||||||
|
guest.wait_vm_boot(None).unwrap();
|
||||||
|
|
||||||
|
// Hotplug test disk
|
||||||
|
assert!(Command::new(clh_command("ch-remote"))
|
||||||
|
.args(&[&format!("--api-socket={}", api_socket)])
|
||||||
|
.args(&[
|
||||||
|
"add-disk",
|
||||||
|
&format!(
|
||||||
|
"path={},num_queues={},queue_size={},direct=on",
|
||||||
|
BLK_IO_TEST_IMG, num_queues, queue_size
|
||||||
|
)
|
||||||
|
])
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap()
|
||||||
|
.wait_timeout(Duration::from_secs(5))
|
||||||
|
.unwrap()
|
||||||
|
.expect("Failed to hotplug test disk image")
|
||||||
|
.success());
|
||||||
|
|
||||||
|
let fio_command = format!(
|
||||||
|
"sudo fio --filename=/dev/vdc --name=test --output-format=json \
|
||||||
|
--direct=1 --bs=4k --ioengine=io_uring --iodepth=64 \
|
||||||
|
--rw={} --runtime={} --numjobs={}",
|
||||||
|
fio_ops, test_timeout, num_queues
|
||||||
|
);
|
||||||
|
let output = guest
|
||||||
|
.ssh_command(&fio_command)
|
||||||
|
.map_err(InfraError::SshCommand)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Parse fio output
|
||||||
|
parse_fio_output(&output, fio_ops, num_queues).unwrap()
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = child.kill();
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(e) => {
|
||||||
|
handle_child_output(Err(e), &output);
|
||||||
|
panic!("test failed!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_iperf3_output() {
|
||||||
|
let output = r#"
|
||||||
|
{
|
||||||
|
"end": {
|
||||||
|
"sum_sent": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 5.000196,
|
||||||
|
"seconds": 5.000196,
|
||||||
|
"bytes": 14973836248,
|
||||||
|
"bits_per_second": 23957198874.604115,
|
||||||
|
"retransmits": 0,
|
||||||
|
"sender": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
assert_eq!(
|
||||||
|
parse_iperf3_output(output.as_bytes(), true).unwrap(),
|
||||||
|
23957198874.604115
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = r#"
|
||||||
|
{
|
||||||
|
"end": {
|
||||||
|
"sum_received": {
|
||||||
|
"start": 0,
|
||||||
|
"end": 5.000626,
|
||||||
|
"seconds": 5.000626,
|
||||||
|
"bytes": 24703557800,
|
||||||
|
"bits_per_second": 39520744482.79,
|
||||||
|
"sender": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
assert_eq!(
|
||||||
|
parse_iperf3_output(output.as_bytes(), false).unwrap(),
|
||||||
|
39520744482.79
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_ethr_latency_output() {
|
||||||
|
let output = r#"{"Time":"2022-02-08T03:52:50Z","Title":"","Type":"INFO","Message":"Using destination: 192.168.249.2, ip: 192.168.249.2, port: 8888"}
|
||||||
|
{"Time":"2022-02-08T03:52:51Z","Title":"","Type":"INFO","Message":"Running latency test: 1000, 1"}
|
||||||
|
{"Time":"2022-02-08T03:52:51Z","Title":"","Type":"LatencyResult","RemoteAddr":"192.168.249.2","Protocol":"TCP","Avg":"80.712us","Min":"61.677us","P50":"257.014us","P90":"74.418us","P95":"107.283us","P99":"119.309us","P999":"142.100us","P9999":"216.341us","Max":"216.341us"}
|
||||||
|
{"Time":"2022-02-08T03:52:52Z","Title":"","Type":"LatencyResult","RemoteAddr":"192.168.249.2","Protocol":"TCP","Avg":"79.826us","Min":"55.129us","P50":"598.996us","P90":"73.849us","P95":"106.552us","P99":"122.152us","P999":"142.459us","P9999":"474.280us","Max":"474.280us"}
|
||||||
|
{"Time":"2022-02-08T03:52:53Z","Title":"","Type":"LatencyResult","RemoteAddr":"192.168.249.2","Protocol":"TCP","Avg":"78.239us","Min":"56.999us","P50":"396.820us","P90":"69.469us","P95":"115.421us","P99":"119.404us","P999":"130.158us","P9999":"258.686us","Max":"258.686us"}"#;
|
||||||
|
|
||||||
|
let ret = parse_ethr_latency_output(output.as_bytes()).unwrap();
|
||||||
|
let reference = vec![80.712_f64, 79.826_f64, 78.239_f64];
|
||||||
|
assert_eq!(ret, reference);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_boot_time_output() {
|
||||||
|
let output = r#"
|
||||||
|
cloud-hypervisor: 161.167103ms: <vcpu0> INFO:vmm/src/vm.rs:392 -- [Debug I/O port: Kernel code 0x40] 0.132 seconds
|
||||||
|
cloud-hypervisor: 613.57361ms: <vcpu0> INFO:vmm/src/vm.rs:392 -- [Debug I/O port: Kernel code 0x41] 0.5845 seconds
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert_eq!(parse_boot_time_output(output.as_bytes()).unwrap(), 0.4525);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_fio_output() {
|
||||||
|
let output = r#"
|
||||||
|
{
|
||||||
|
"jobs" : [
|
||||||
|
{
|
||||||
|
"read" : {
|
||||||
|
"io_bytes" : 1965273088,
|
||||||
|
"io_kbytes" : 1919212,
|
||||||
|
"bw_bytes" : 392976022,
|
||||||
|
"bw" : 383765,
|
||||||
|
"iops" : 95941.411718,
|
||||||
|
"runtime" : 5001,
|
||||||
|
"total_ios" : 479803,
|
||||||
|
"short_ios" : 0,
|
||||||
|
"drop_ios" : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let bps = 1965273088_f64 / (5001_f64 / 1000_f64);
|
||||||
|
assert_eq!(
|
||||||
|
parse_fio_output(output, &FioOps::RandomRead, 1).unwrap(),
|
||||||
|
bps
|
||||||
|
);
|
||||||
|
assert_eq!(parse_fio_output(output, &FioOps::Read, 1).unwrap(), bps);
|
||||||
|
|
||||||
|
let output = r#"
|
||||||
|
{
|
||||||
|
"jobs" : [
|
||||||
|
{
|
||||||
|
"write" : {
|
||||||
|
"io_bytes" : 1172783104,
|
||||||
|
"io_kbytes" : 1145296,
|
||||||
|
"bw_bytes" : 234462835,
|
||||||
|
"bw" : 228967,
|
||||||
|
"iops" : 57241.903239,
|
||||||
|
"runtime" : 5002,
|
||||||
|
"total_ios" : 286324,
|
||||||
|
"short_ios" : 0,
|
||||||
|
"drop_ios" : 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"write" : {
|
||||||
|
"io_bytes" : 1172234240,
|
||||||
|
"io_kbytes" : 1144760,
|
||||||
|
"bw_bytes" : 234353106,
|
||||||
|
"bw" : 228860,
|
||||||
|
"iops" : 57215.113954,
|
||||||
|
"runtime" : 5002,
|
||||||
|
"total_ios" : 286190,
|
||||||
|
"short_ios" : 0,
|
||||||
|
"drop_ios" : 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let bps = 1172783104_f64 / (5002_f64 / 1000_f64) + 1172234240_f64 / (5002_f64 / 1000_f64);
|
||||||
|
assert_eq!(
|
||||||
|
parse_fio_output(output, &FioOps::RandomWrite, 2).unwrap(),
|
||||||
|
bps
|
||||||
|
);
|
||||||
|
assert_eq!(parse_fio_output(output, &FioOps::Write, 2).unwrap(), bps);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ path = "src/qcow.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
remain = "0.2.2"
|
remain = "0.2.2"
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ version = "0.1.0"
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
|
|||||||
220
release-notes.md
220
release-notes.md
@@ -1,11 +1,29 @@
|
|||||||
|
- [v22.0](#v220)
|
||||||
|
- [GDB Debug Stub Support](#gdb-debug-stub-support)
|
||||||
|
- [`virtio-iommu` Backed Segments](#virtio-iommu-backed-segments)
|
||||||
|
- [Before Boot Configuration Changes](#before-boot-configuration-changes)
|
||||||
|
- [`virtio-balloon` Free Page Reporting](#virtio-balloon-free-page-reporting)
|
||||||
|
- [Support for Direct Kernel Booting with TDX](#support-for-direct-kernel-booting-with-tdx)
|
||||||
|
- [PMU Support for AArch64](#pmu-support-for-aarch64)
|
||||||
|
- [Documentation Under CC-BY-4.0 Licese](#documentation-under-cc-by-40-licese)
|
||||||
|
- [Deprecation of "Classic" `virtiofsd`](#deprecation-of-classic-virtiofsd)
|
||||||
|
- [Notable Bug Fixes](#notable-bug-fixes)
|
||||||
|
- [Contributors](#contributors)
|
||||||
|
- [v21.0](#v210)
|
||||||
|
- [Efficient Local Live Migration (for Live Upgrade)](#efficient-local-live-migration-for-live-upgrade)
|
||||||
|
- [Recommended Kernel is Now 5.15](#recommended-kernel-is-now-515)
|
||||||
|
- [Notable Bug fixes](#notable-bug-fixes-1)
|
||||||
|
- [Contributors](#contributors-1)
|
||||||
|
- [v20.2](#v202)
|
||||||
|
- [v20.1](#v201)
|
||||||
- [v20.0](#v200)
|
- [v20.0](#v200)
|
||||||
- [Multiple PCI segments support](#multiple-pci-segments-support)
|
- [Multiple PCI segments support](#multiple-pci-segments-support)
|
||||||
- [CPU pinning](#cpu-pinning)
|
- [CPU pinning](#cpu-pinning)
|
||||||
- [Improved VFIO support](#improved-vfio-support)
|
- [Improved VFIO support](#improved-vfio-support)
|
||||||
- [Safer code](#safer-code)
|
- [Safer code](#safer-code)
|
||||||
- [Extended documentation](#extended-documentation)
|
- [Extended documentation](#extended-documentation)
|
||||||
- [Notable bug fixes](#notable-bug-fixes)
|
- [Notable bug fixes](#notable-bug-fixes-2)
|
||||||
- [Contributors](#contributors)
|
- [Contributors](#contributors-2)
|
||||||
- [v19.0](#v190)
|
- [v19.0](#v190)
|
||||||
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
- [Improved PTY handling for serial and `virtio-console`](#improved-pty-handling-for-serial-and-virtio-console)
|
||||||
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
- [PCI boot time optimisations](#pci-boot-time-optimisations)
|
||||||
@@ -13,8 +31,8 @@
|
|||||||
- [Live migration enhancements](#live-migration-enhancements)
|
- [Live migration enhancements](#live-migration-enhancements)
|
||||||
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
- [`virtio-mem` support with `vfio-user`](#virtio-mem-support-with-vfio-user)
|
||||||
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
- [AArch64 for `virtio-iommu`](#aarch64-for-virtio-iommu)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-1)
|
- [Notable bug fixes](#notable-bug-fixes-3)
|
||||||
- [Contributors](#contributors-1)
|
- [Contributors](#contributors-3)
|
||||||
- [v18.0](#v180)
|
- [v18.0](#v180)
|
||||||
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
- [Experimental User Device (`vfio-user`) support](#experimental-user-device-vfio-user-support)
|
||||||
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
- [Migration support for `vhost-user` devices](#migration-support-for-vhost-user-devices)
|
||||||
@@ -24,23 +42,23 @@
|
|||||||
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
- [Live migration on MSHV hypervisor](#live-migration-on-mshv-hypervisor)
|
||||||
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
- [AArch64 CPU topology support](#aarch64-cpu-topology-support)
|
||||||
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
- [Power button support on AArch64](#power-button-support-on-aarch64)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-2)
|
- [Notable bug fixes](#notable-bug-fixes-4)
|
||||||
- [Contributors](#contributors-2)
|
- [Contributors](#contributors-4)
|
||||||
- [v17.0](#v170)
|
- [v17.0](#v170)
|
||||||
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
- [ARM64 NUMA support using ACPI](#arm64-numa-support-using-acpi)
|
||||||
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
- [`Seccomp` support for MSHV backend](#seccomp-support-for-mshv-backend)
|
||||||
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
- [Hotplug of `macvtap` devices](#hotplug-of-macvtap-devices)
|
||||||
- [Improved SGX support](#improved-sgx-support)
|
- [Improved SGX support](#improved-sgx-support)
|
||||||
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
- [Inflight tracking for `vhost-user` devices](#inflight-tracking-for-vhost-user-devices)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-3)
|
- [Notable bug fixes](#notable-bug-fixes-5)
|
||||||
- [Contributors](#contributors-3)
|
- [Contributors](#contributors-5)
|
||||||
- [v16.0](#v160)
|
- [v16.0](#v160)
|
||||||
- [Improved live migration support](#improved-live-migration-support)
|
- [Improved live migration support](#improved-live-migration-support)
|
||||||
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
- [Improved `vhost-user` support](#improved-vhost-user-support)
|
||||||
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
- [ARM64 ACPI and UEFI support](#arm64-acpi-and-uefi-support)
|
||||||
- [Notable bug fixes](#notable-bug-fixes-4)
|
- [Notable bug fixes](#notable-bug-fixes-6)
|
||||||
- [Removed functionality](#removed-functionality)
|
- [Removed functionality](#removed-functionality)
|
||||||
- [Contributors](#contributors-4)
|
- [Contributors](#contributors-6)
|
||||||
- [v15.0](#v150)
|
- [v15.0](#v150)
|
||||||
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
- [Version numbering and stability guarantees](#version-numbering-and-stability-guarantees)
|
||||||
- [Network device rate limiting](#network-device-rate-limiting)
|
- [Network device rate limiting](#network-device-rate-limiting)
|
||||||
@@ -48,7 +66,7 @@
|
|||||||
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
- [`--api-socket` supports file descriptor parameter](#--api-socket-supports-file-descriptor-parameter)
|
||||||
- [Bug fixes](#bug-fixes)
|
- [Bug fixes](#bug-fixes)
|
||||||
- [Deprecations](#deprecations)
|
- [Deprecations](#deprecations)
|
||||||
- [Contributors](#contributors-5)
|
- [Contributors](#contributors-7)
|
||||||
- [v0.14.1](#v0141)
|
- [v0.14.1](#v0141)
|
||||||
- [v0.14.0](#v0140)
|
- [v0.14.0](#v0140)
|
||||||
- [Structured event monitoring](#structured-event-monitoring)
|
- [Structured event monitoring](#structured-event-monitoring)
|
||||||
@@ -58,7 +76,7 @@
|
|||||||
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
- [PTY control for serial and `virtio-console`](#pty-control-for-serial-and-virtio-console)
|
||||||
- [Block device rate limiting](#block-device-rate-limiting)
|
- [Block device rate limiting](#block-device-rate-limiting)
|
||||||
- [Deprecations](#deprecations-1)
|
- [Deprecations](#deprecations-1)
|
||||||
- [Contributors](#contributors-6)
|
- [Contributors](#contributors-8)
|
||||||
- [v0.13.0](#v0130)
|
- [v0.13.0](#v0130)
|
||||||
- [Wider VFIO device support](#wider-vfio-device-support)
|
- [Wider VFIO device support](#wider-vfio-device-support)
|
||||||
- [Improved huge page support](#improved-huge-page-support)
|
- [Improved huge page support](#improved-huge-page-support)
|
||||||
@@ -66,13 +84,13 @@
|
|||||||
- [VHD disk image support](#vhd-disk-image-support)
|
- [VHD disk image support](#vhd-disk-image-support)
|
||||||
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
- [Improved Virtio device threading](#improved-virtio-device-threading)
|
||||||
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
- [Clean shutdown support via synthetic power button](#clean-shutdown-support-via-synthetic-power-button)
|
||||||
- [Contributors](#contributors-7)
|
- [Contributors](#contributors-9)
|
||||||
- [v0.12.0](#v0120)
|
- [v0.12.0](#v0120)
|
||||||
- [ARM64 enhancements](#arm64-enhancements)
|
- [ARM64 enhancements](#arm64-enhancements)
|
||||||
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
- [Removal of `vhost-user-net` and `vhost-user-block` self spawning](#removal-of-vhost-user-net-and-vhost-user-block-self-spawning)
|
||||||
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
- [Migration of `vhost-user-fs` backend](#migration-of-vhost-user-fs-backend)
|
||||||
- [Enhanced "info" API](#enhanced-info-api)
|
- [Enhanced "info" API](#enhanced-info-api)
|
||||||
- [Contributors](#contributors-8)
|
- [Contributors](#contributors-10)
|
||||||
- [v0.11.0](#v0110)
|
- [v0.11.0](#v0110)
|
||||||
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
- [`io_uring` support by default for `virtio-block`](#io_uring-support-by-default-for-virtio-block)
|
||||||
- [Windows Guest Support](#windows-guest-support)
|
- [Windows Guest Support](#windows-guest-support)
|
||||||
@@ -84,15 +102,15 @@
|
|||||||
- [Default Log Level Changed](#default-log-level-changed)
|
- [Default Log Level Changed](#default-log-level-changed)
|
||||||
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
- [New `--balloon` Parameter Added](#new---balloon-parameter-added)
|
||||||
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
- [Experimental `virtio-watchdog` Support](#experimental-virtio-watchdog-support)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-5)
|
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
||||||
- [Contributors](#contributors-9)
|
- [Contributors](#contributors-11)
|
||||||
- [v0.10.0](#v0100)
|
- [v0.10.0](#v0100)
|
||||||
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
- [`virtio-block` Support for Multiple Descriptors](#virtio-block-support-for-multiple-descriptors)
|
||||||
- [Memory Zones](#memory-zones)
|
- [Memory Zones](#memory-zones)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements)
|
||||||
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
- [Preliminary KVM HyperV Emulation Control](#preliminary-kvm-hyperv-emulation-control)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-6)
|
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
||||||
- [Contributors](#contributors-10)
|
- [Contributors](#contributors-12)
|
||||||
- [v0.9.0](#v090)
|
- [v0.9.0](#v090)
|
||||||
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
- [`io_uring` Based Block Device Support](#io_uring-based-block-device-support)
|
||||||
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
- [Block and Network Device Statistics](#block-and-network-device-statistics)
|
||||||
@@ -105,17 +123,17 @@
|
|||||||
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
- [Enhancements to ARM64 Support](#enhancements-to-arm64-support)
|
||||||
- [Intel SGX Support](#intel-sgx-support)
|
- [Intel SGX Support](#intel-sgx-support)
|
||||||
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
- [`Seccomp` Sandbox Improvements](#seccomp-sandbox-improvements-1)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-7)
|
- [Notable Bug Fixes](#notable-bug-fixes-9)
|
||||||
- [Contributors](#contributors-11)
|
- [Contributors](#contributors-13)
|
||||||
- [v0.8.0](#v080)
|
- [v0.8.0](#v080)
|
||||||
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
- [Experimental Snapshot and Restore Support](#experimental-snapshot-and-restore-support)
|
||||||
- [Experimental ARM64 Support](#experimental-arm64-support)
|
- [Experimental ARM64 Support](#experimental-arm64-support)
|
||||||
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
- [Support for Using 5-level Paging in Guests](#support-for-using-5-level-paging-in-guests)
|
||||||
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
- [Virtio Device Interrupt Suppression for Network Devices](#virtio-device-interrupt-suppression-for-network-devices)
|
||||||
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
- [`vhost_user_fs` Improvements](#vhost_user_fs-improvements)
|
||||||
- [Notable Bug Fixes](#notable-bug-fixes-8)
|
- [Notable Bug Fixes](#notable-bug-fixes-10)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes)
|
- [Command Line and API Changes](#command-line-and-api-changes)
|
||||||
- [Contributors](#contributors-12)
|
- [Contributors](#contributors-14)
|
||||||
- [v0.7.0](#v070)
|
- [v0.7.0](#v070)
|
||||||
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
- [Block, Network, Persistent Memory (PMEM), VirtioFS and Vsock hotplug](#block-network-persistent-memory-pmem-virtiofs-and-vsock-hotplug)
|
||||||
- [Alternative `libc` Support](#alternative-libc-support)
|
- [Alternative `libc` Support](#alternative-libc-support)
|
||||||
@@ -125,14 +143,14 @@
|
|||||||
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
- [`Seccomp` Sandboxing](#seccomp-sandboxing)
|
||||||
- [Updated Distribution Support](#updated-distribution-support)
|
- [Updated Distribution Support](#updated-distribution-support)
|
||||||
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
- [Command Line and API Changes](#command-line-and-api-changes-1)
|
||||||
- [Contributors](#contributors-13)
|
- [Contributors](#contributors-15)
|
||||||
- [v0.6.0](#v060)
|
- [v0.6.0](#v060)
|
||||||
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
- [Directly Assigned Devices Hotplug](#directly-assigned-devices-hotplug)
|
||||||
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
- [Shared Filesystem Improvements](#shared-filesystem-improvements)
|
||||||
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
- [Block and Networking IO Self Offloading](#block-and-networking-io-self-offloading)
|
||||||
- [Command Line Interface](#command-line-interface)
|
- [Command Line Interface](#command-line-interface)
|
||||||
- [PVH Boot](#pvh-boot)
|
- [PVH Boot](#pvh-boot)
|
||||||
- [Contributors](#contributors-14)
|
- [Contributors](#contributors-16)
|
||||||
- [v0.5.1](#v051)
|
- [v0.5.1](#v051)
|
||||||
- [v0.5.0](#v050)
|
- [v0.5.0](#v050)
|
||||||
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
- [Virtual Machine Dynamic Resizing](#virtual-machine-dynamic-resizing)
|
||||||
@@ -140,7 +158,7 @@
|
|||||||
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
- [New Interrupt Management Framework](#new-interrupt-management-framework)
|
||||||
- [Development Tools](#development-tools)
|
- [Development Tools](#development-tools)
|
||||||
- [Kata Containers Integration](#kata-containers-integration)
|
- [Kata Containers Integration](#kata-containers-integration)
|
||||||
- [Contributors](#contributors-15)
|
- [Contributors](#contributors-17)
|
||||||
- [v0.4.0](#v040)
|
- [v0.4.0](#v040)
|
||||||
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
- [Dynamic virtual CPUs addition](#dynamic-virtual-cpus-addition)
|
||||||
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
- [Programmatic firmware tables generation](#programmatic-firmware-tables-generation)
|
||||||
@@ -149,7 +167,7 @@
|
|||||||
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
- [Userspace IOAPIC by default](#userspace-ioapic-by-default)
|
||||||
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
- [PCI BAR reprogramming](#pci-bar-reprogramming)
|
||||||
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
- [New `cloud-hypervisor` organization](#new-cloud-hypervisor-organization)
|
||||||
- [Contributors](#contributors-16)
|
- [Contributors](#contributors-18)
|
||||||
- [v0.3.0](#v030)
|
- [v0.3.0](#v030)
|
||||||
- [Block device offloading](#block-device-offloading)
|
- [Block device offloading](#block-device-offloading)
|
||||||
- [Network device backend](#network-device-backend)
|
- [Network device backend](#network-device-backend)
|
||||||
@@ -176,6 +194,156 @@
|
|||||||
- [Unit testing](#unit-testing)
|
- [Unit testing](#unit-testing)
|
||||||
- [Integration tests parallelization](#integration-tests-parallelization)
|
- [Integration tests parallelization](#integration-tests-parallelization)
|
||||||
|
|
||||||
|
# v22.0
|
||||||
|
|
||||||
|
This release has been tracked through the [v21.0
|
||||||
|
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/24).
|
||||||
|
|
||||||
|
### GDB Debug Stub Support
|
||||||
|
|
||||||
|
Cloud Hypervisor can now be used as debug target with GDB. This is controlled
|
||||||
|
by the `gdb` compile time feature and details of how to use it can be found in
|
||||||
|
the [gdb
|
||||||
|
documentation](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/gdb.md).
|
||||||
|
|
||||||
|
|
||||||
|
### `virtio-iommu` Backed Segments
|
||||||
|
|
||||||
|
In order to facilitate hotplug devices that require being behind an IOMMU (e.g.
|
||||||
|
QAT) there is a new option `--platform iommu_segments=<list_of_segments>` that
|
||||||
|
will place all the specified segments behind the IOMMU.
|
||||||
|
|
||||||
|
### Before Boot Configuration Changes
|
||||||
|
|
||||||
|
It is now possible to change the VM configuration (e.g. add or remove devices,
|
||||||
|
resize) before the VM is booted.
|
||||||
|
|
||||||
|
|
||||||
|
### `virtio-balloon` Free Page Reporting
|
||||||
|
|
||||||
|
If `--balloon free_page_reporting=on` is used then the guest can report pages
|
||||||
|
that is it not using to the VMM. The VMM will then notify the host OS that
|
||||||
|
those pages are no longer in use and can be freed. This can result in improved
|
||||||
|
memory density.
|
||||||
|
|
||||||
|
### Support for Direct Kernel Booting with TDX
|
||||||
|
|
||||||
|
Through the use of `TD-Shim` lightweight firmware it is now possible to
|
||||||
|
directly boot into the kernel with TDX. The [TDX
|
||||||
|
documentation](https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/intel_tdx.md#tdshim)
|
||||||
|
has been updated for this usage.
|
||||||
|
|
||||||
|
### PMU Support for AArch64
|
||||||
|
|
||||||
|
A PMU is now available on AArch64 for guest performance profiling. This will be
|
||||||
|
exposed automatically if available from the host.
|
||||||
|
|
||||||
|
### Documentation Under CC-BY-4.0 Licese
|
||||||
|
|
||||||
|
The documentation is now licensed under the "Creative Commons Attribution 4.0
|
||||||
|
International" license which is aligned with the project charter under the
|
||||||
|
Linux Foundation.
|
||||||
|
|
||||||
|
### Deprecation of "Classic" `virtiofsd`
|
||||||
|
|
||||||
|
The use of the Rust based [virtiofsd](https://gitlab.com/virtio-fs/virtiofsd)
|
||||||
|
is now recommended and we are no longer testing against the C based "classic"
|
||||||
|
version.
|
||||||
|
|
||||||
|
### Notable Bug Fixes
|
||||||
|
|
||||||
|
* Can now be used on kernels without `AF_INET` support (#3785)
|
||||||
|
* `virtio-balloon` size is now validated against guest RAM size (#3689)
|
||||||
|
* Ensure that I/O related KVM VM Exits are correctly handled (#3677)
|
||||||
|
* Multiple TAP file descriptors can be used for `virtio-net` device hotplug (#3607)
|
||||||
|
* Minor API improvements and fixes (#3756, #3766, #3647, #3578)
|
||||||
|
* Fix sporadic seccomp violation from glibc memory freeing (#3610, #3609)
|
||||||
|
* Fix Windows 11 on AArch64 due to wider MSI-X register accesses (#3714, #3720)
|
||||||
|
* Ensure `vhost-user` features are correct across migration (#3737)
|
||||||
|
* Improved vCPU topology on AArch64 (#3735, #3733)
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to everyone who has contributed to our release:
|
||||||
|
|
||||||
|
* Akira Moroo <retrage01@gmail.com>
|
||||||
|
* Barret Rhoden <brho@google.com>
|
||||||
|
* Bo Chen <chen.bo@intel.com>
|
||||||
|
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
|
||||||
|
* Feng Ye <yefeng@smartx.com>
|
||||||
|
* Henry Wang <Henry.Wang@arm.com>
|
||||||
|
* Jianyong Wu <jianyong.wu@arm.com>
|
||||||
|
* lizhaoxin1 <Lxiaoyouling@163.com>
|
||||||
|
* Michael Zhao <michael.zhao@arm.com>
|
||||||
|
* Rob Bradford <robert.bradford@intel.com>
|
||||||
|
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||||
|
* Wei Liu <liuwe@microsoft.com>
|
||||||
|
|
||||||
|
# v21.0
|
||||||
|
|
||||||
|
This release has been tracked through the [v21.0
|
||||||
|
project](https://github.com/cloud-hypervisor/cloud-hypervisor/projects/24).
|
||||||
|
|
||||||
|
### Efficient Local Live Migration (for Live Upgrade)
|
||||||
|
|
||||||
|
In order to support fast live upgrade of the VMM an optimised path has been
|
||||||
|
added in which the memory for the VM is not compared from source to
|
||||||
|
destination. This is activated by passing `--local` to the `ch-remote
|
||||||
|
send-migration` command. This means that the live upgrade can complete in the
|
||||||
|
order of 50ms vs 3s. (#3566)
|
||||||
|
|
||||||
|
### Recommended Kernel is Now 5.15
|
||||||
|
|
||||||
|
Due to an issue in the `virtio-net` code in 5.14 the recommended Linux kernel
|
||||||
|
is now 5.15. (#3530)
|
||||||
|
|
||||||
|
### Notable Bug fixes
|
||||||
|
|
||||||
|
* Multiple fixes were made to the OpenAPI YAML file to match the implementaion (#3555,#3562)
|
||||||
|
* Avoid live migration deadlock when triggered during the kernel boot (#3585)
|
||||||
|
* Support live migration within firmware (#3586)
|
||||||
|
* Validate the `virtio-net` desciptor chain (#3548)
|
||||||
|
* `direct=on` (`O_DIRECT`) can now be used with a guest that makes unaligned accesses (e.g. firmware) (#3587)
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Many thanks to everyone who has contributed to our release:
|
||||||
|
|
||||||
|
* Anatol Belski <anbelski@linux.microsoft.com>
|
||||||
|
* Barret Rhoden <brho@google.com>
|
||||||
|
* Bo Chen <chen.bo@intel.com>
|
||||||
|
* Fabiano Fidêncio <fabiano.fidencio@intel.com>
|
||||||
|
* Henry Wang <Henry.Wang@arm.com>
|
||||||
|
* Liang Zhou <zhoul110@chinatelecom.cn>
|
||||||
|
* Michael Zhao <michael.zhao@arm.com>
|
||||||
|
* Muhammad Falak R Wani <falakreyaz@gmail.com>
|
||||||
|
* Muminul Islam <muislam@microsoft.com>
|
||||||
|
* Rob Bradford <robert.bradford@intel.com>
|
||||||
|
* Sebastien Boeuf <sebastien.boeuf@intel.com>
|
||||||
|
* Wei Liu <liuwe@microsoft.com>
|
||||||
|
* Ziye Yang <ziye.yang@intel.com>
|
||||||
|
|
||||||
|
# v20.2
|
||||||
|
|
||||||
|
This is a bug fix release. The following issues have been addressed:
|
||||||
|
|
||||||
|
* Don't error out when setting up the SIGWINCH handler (for console resize)
|
||||||
|
when this fails due to older kernel (#3456)
|
||||||
|
* Seccomp rules were refined to remove syscalls that are now unused
|
||||||
|
* Fix reboot on older host kernels when SIGWINCH handler was not initialised
|
||||||
|
(#3496)
|
||||||
|
* Fix virtio-vsock blocking issue (#3497)
|
||||||
|
|
||||||
|
# v20.1
|
||||||
|
|
||||||
|
This is a bug fix release. The following issues have been addressed:
|
||||||
|
|
||||||
|
* Networking performance regression with `virtio-net` (#3450)
|
||||||
|
* Limit file descriptors sent in `vfio-user` support (#3401)
|
||||||
|
* Fully advertise PCI MMIO config regions in ACPI tables (#3432)
|
||||||
|
* Set the TSS and KVM identity maps so they don't overlap with firmware RAM
|
||||||
|
* Correctly update the `DeviceTree` on restore
|
||||||
|
|
||||||
# v20.0
|
# v20.0
|
||||||
|
|
||||||
This release has been tracked through the [v20.0
|
This release has been tracked through the [v20.0
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
|
# When changing this file don't forget to update the tag name in the
|
||||||
|
# .github/workflows/docker-image.yaml file if doing multiple per day
|
||||||
|
|
||||||
FROM ubuntu:20.04 as dev
|
FROM ubuntu:20.04 as dev
|
||||||
|
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG RUST_TOOLCHAIN="1.56.1"
|
ARG RUST_TOOLCHAIN="1.59.0"
|
||||||
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
ARG CLH_SRC_DIR="/cloud-hypervisor"
|
||||||
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
ARG CLH_BUILD_DIR="$CLH_SRC_DIR/build"
|
||||||
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
ARG CARGO_REGISTRY_DIR="$CLH_BUILD_DIR/cargo_registry"
|
||||||
@@ -17,7 +20,6 @@ RUN apt-get update \
|
|||||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||||
build-essential \
|
build-essential \
|
||||||
bc \
|
bc \
|
||||||
docker.io \
|
|
||||||
curl \
|
curl \
|
||||||
wget \
|
wget \
|
||||||
sudo \
|
sudo \
|
||||||
@@ -29,7 +31,6 @@ RUN apt-get update \
|
|||||||
bison \
|
bison \
|
||||||
libelf-dev \
|
libelf-dev \
|
||||||
qemu-utils \
|
qemu-utils \
|
||||||
qemu-system \
|
|
||||||
libglib2.0-dev \
|
libglib2.0-dev \
|
||||||
libpixman-1-dev \
|
libpixman-1-dev \
|
||||||
libseccomp-dev \
|
libseccomp-dev \
|
||||||
@@ -44,6 +45,11 @@ RUN apt-get update \
|
|||||||
openvswitch-switch-dpdk \
|
openvswitch-switch-dpdk \
|
||||||
python3-distutils \
|
python3-distutils \
|
||||||
uuid-dev \
|
uuid-dev \
|
||||||
|
iperf3 \
|
||||||
|
zip \
|
||||||
|
git-core \
|
||||||
|
dnsmasq \
|
||||||
|
dmsetup \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
@@ -66,7 +72,7 @@ RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
|||||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq \
|
||||||
libcap2-bin \
|
libcap2-bin \
|
||||||
libguestfs-tools \
|
libguestfs-tools \
|
||||||
linux-image-5.8.0-63-generic \
|
linux-image-generic \
|
||||||
autotools-dev \
|
autotools-dev \
|
||||||
autoconf \
|
autoconf \
|
||||||
automake \
|
automake \
|
||||||
@@ -86,12 +92,11 @@ ENV OPENSSL_INCLUDE_DIR=/usr/include/
|
|||||||
|
|
||||||
# Install the rust toolchain
|
# Install the rust toolchain
|
||||||
RUN export ARCH="$(uname -m)" \
|
RUN export ARCH="$(uname -m)" \
|
||||||
&& nohup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" \
|
&& nohup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
|
||||||
&& rustup target add $ARCH-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
&& rustup target add $ARCH-unknown-linux-musl --toolchain "$RUST_TOOLCHAIN" \
|
||||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup toolchain add $RUST_TOOLCHAIN-x86_64-unknown-linux-musl; fi \
|
&& if [ "$TARGETARCH" = "amd64" ]; then rustup toolchain add --profile minimal $RUST_TOOLCHAIN-x86_64-unknown-linux-musl; fi \
|
||||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add rustfmt; fi \
|
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add rustfmt; fi \
|
||||||
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
|
&& if [ "$TARGETARCH" = "amd64" ]; then rustup component add clippy; fi \
|
||||||
&& cargo install cargo-audit \
|
|
||||||
&& rm -rf "$CARGO_HOME/registry" \
|
&& rm -rf "$CARGO_HOME/registry" \
|
||||||
&& ln -s "$CARGO_REGISTRY_DIR" "$CARGO_HOME/registry" \
|
&& ln -s "$CARGO_REGISTRY_DIR" "$CARGO_HOME/registry" \
|
||||||
&& rm -rf "$CARGO_HOME/git" \
|
&& rm -rf "$CARGO_HOME/git" \
|
||||||
@@ -102,25 +107,16 @@ RUN echo 'source $CARGO_HOME/env' >> $HOME/.bashrc \
|
|||||||
&& mkdir $HOME/.cargo \
|
&& mkdir $HOME/.cargo \
|
||||||
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
&& ln -s $CARGO_HOME/env $HOME/.cargo/env
|
||||||
|
|
||||||
# install virtiofsd
|
|
||||||
RUN git clone --depth 1 https://gitlab.com/virtio-fs/qemu.git -b qemu5.0-virtiofs-dax \
|
|
||||||
&& cd qemu \
|
|
||||||
&& ./configure --prefix=$PWD --target-list=x86_64-softmmu \
|
|
||||||
&& make virtiofsd -j `nproc` \
|
|
||||||
&& cp virtiofsd /usr/local/bin \
|
|
||||||
&& cd .. && rm -rf qemu
|
|
||||||
|
|
||||||
# install SPDK NVMe
|
# install SPDK NVMe
|
||||||
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
|
# only for 'x86_64' platform images as 'docker buildx' can't build 'spdk'
|
||||||
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||||
git clone https://github.com/spdk/spdk \
|
git clone https://github.com/spdk/spdk \
|
||||||
&& cd spdk \
|
&& cd spdk \
|
||||||
&& git checkout a827fd7eeca67209d4c0aaad9a3ed55692e7e36e \
|
&& git checkout 59f3cdacb13bd2a19c4a86be04792b0ee4491172 \
|
||||||
&& git submodule update --init \
|
&& git submodule update --init \
|
||||||
&& sed -i 's/pip3 install meson/pip3 install meson==0.59.2/g' scripts/pkgdep/ubuntu.sh \
|
|
||||||
&& sed -i 's/meson/meson==0.59.2/g' scripts/pkgdep/requirements.txt \
|
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& ./scripts/pkgdep.sh \
|
&& ./scripts/pkgdep.sh \
|
||||||
|
&& apt-get clean \
|
||||||
&& ./configure --with-vfio-user \
|
&& ./configure --with-vfio-user \
|
||||||
&& make -j `nproc` \
|
&& make -j `nproc` \
|
||||||
&& mkdir /usr/local/bin/spdk-nvme \
|
&& mkdir /usr/local/bin/spdk-nvme \
|
||||||
@@ -128,3 +124,10 @@ RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
|||||||
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
&& cp ./scripts/rpc.py /usr/local/bin/spdk-nvme \
|
||||||
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
|
&& cp -r ./scripts/rpc /usr/local/bin/spdk-nvme \
|
||||||
&& cd .. && rm -rf spdk; fi
|
&& cd .. && rm -rf spdk; fi
|
||||||
|
|
||||||
|
# install ethr tool for performance tests
|
||||||
|
RUN if [ "$TARGETARCH" = "amd64" ]; then \
|
||||||
|
wget 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.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/arm64 5.14.0 Kernel Configuration
|
# Linux/arm64 5.15.12 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
|
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0"
|
||||||
CONFIG_CC_IS_GCC=y
|
CONFIG_CC_IS_GCC=y
|
||||||
@@ -25,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
|
|||||||
#
|
#
|
||||||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||||
# CONFIG_COMPILE_TEST is not set
|
# CONFIG_COMPILE_TEST is not set
|
||||||
|
# CONFIG_WERROR is not set
|
||||||
CONFIG_LOCALVERSION=""
|
CONFIG_LOCALVERSION=""
|
||||||
# CONFIG_LOCALVERSION_AUTO is not set
|
# CONFIG_LOCALVERSION_AUTO is not set
|
||||||
CONFIG_BUILD_SALT=""
|
CONFIG_BUILD_SALT=""
|
||||||
@@ -133,6 +134,7 @@ CONFIG_RCU_NEED_SEGCBLIST=y
|
|||||||
CONFIG_LOG_BUF_SHIFT=21
|
CONFIG_LOG_BUF_SHIFT=21
|
||||||
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
||||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
||||||
|
# CONFIG_PRINTK_INDEX is not set
|
||||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -202,7 +204,6 @@ CONFIG_SYSFS_SYSCALL=y
|
|||||||
CONFIG_FHANDLE=y
|
CONFIG_FHANDLE=y
|
||||||
CONFIG_POSIX_TIMERS=y
|
CONFIG_POSIX_TIMERS=y
|
||||||
CONFIG_PRINTK=y
|
CONFIG_PRINTK=y
|
||||||
CONFIG_PRINTK_NMI=y
|
|
||||||
CONFIG_BUG=y
|
CONFIG_BUG=y
|
||||||
CONFIG_ELF_CORE=y
|
CONFIG_ELF_CORE=y
|
||||||
CONFIG_BASE_FULL=y
|
CONFIG_BASE_FULL=y
|
||||||
@@ -265,7 +266,6 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MAX=16
|
|||||||
CONFIG_STACKTRACE_SUPPORT=y
|
CONFIG_STACKTRACE_SUPPORT=y
|
||||||
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
CONFIG_ILLEGAL_POINTER_VALUE=0xdead000000000000
|
||||||
CONFIG_LOCKDEP_SUPPORT=y
|
CONFIG_LOCKDEP_SUPPORT=y
|
||||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
|
||||||
CONFIG_GENERIC_BUG=y
|
CONFIG_GENERIC_BUG=y
|
||||||
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
CONFIG_GENERIC_BUG_RELATIVE_POINTERS=y
|
||||||
CONFIG_GENERIC_HWEIGHT=y
|
CONFIG_GENERIC_HWEIGHT=y
|
||||||
@@ -431,8 +431,10 @@ CONFIG_ARM64_CNP=y
|
|||||||
#
|
#
|
||||||
CONFIG_ARM64_PTR_AUTH=y
|
CONFIG_ARM64_PTR_AUTH=y
|
||||||
CONFIG_ARM64_PTR_AUTH_KERNEL=y
|
CONFIG_ARM64_PTR_AUTH_KERNEL=y
|
||||||
|
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y
|
||||||
CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
|
CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
|
||||||
CONFIG_AS_HAS_PAC=y
|
CONFIG_AS_HAS_PAC=y
|
||||||
|
CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y
|
||||||
# end of ARMv8.3 architectural features
|
# end of ARMv8.3 architectural features
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -446,9 +448,13 @@ CONFIG_ARM64_TLB_RANGE=y
|
|||||||
#
|
#
|
||||||
# ARMv8.5 architectural features
|
# ARMv8.5 architectural features
|
||||||
#
|
#
|
||||||
|
CONFIG_AS_HAS_ARMV8_5=y
|
||||||
CONFIG_ARM64_BTI=y
|
CONFIG_ARM64_BTI=y
|
||||||
|
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET_BTI=y
|
||||||
CONFIG_ARM64_E0PD=y
|
CONFIG_ARM64_E0PD=y
|
||||||
CONFIG_ARCH_RANDOM=y
|
CONFIG_ARCH_RANDOM=y
|
||||||
|
CONFIG_ARM64_AS_HAS_MTE=y
|
||||||
|
CONFIG_ARM64_MTE=y
|
||||||
# end of ARMv8.5 architectural features
|
# end of ARMv8.5 architectural features
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -462,6 +468,8 @@ CONFIG_ARM64_SVE=y
|
|||||||
CONFIG_RELOCATABLE=y
|
CONFIG_RELOCATABLE=y
|
||||||
CONFIG_RANDOMIZE_BASE=y
|
CONFIG_RANDOMIZE_BASE=y
|
||||||
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
|
CONFIG_RANDOMIZE_MODULE_REGION_FULL=y
|
||||||
|
CONFIG_CC_HAVE_STACKPROTECTOR_SYSREG=y
|
||||||
|
CONFIG_STACKPROTECTOR_PER_TASK=y
|
||||||
# end of Kernel Features
|
# end of Kernel Features
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -543,49 +551,6 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
|
|||||||
# end of CPU Frequency scaling
|
# end of CPU Frequency scaling
|
||||||
# end of CPU Power Management
|
# end of CPU Power Management
|
||||||
|
|
||||||
#
|
|
||||||
# Firmware Drivers
|
|
||||||
#
|
|
||||||
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
|
||||||
# CONFIG_ARM_SCPI_PROTOCOL is not set
|
|
||||||
# CONFIG_ARM_SDE_INTERFACE is not set
|
|
||||||
CONFIG_FIRMWARE_MEMMAP=y
|
|
||||||
CONFIG_DMIID=y
|
|
||||||
CONFIG_DMI_SYSFS=y
|
|
||||||
# CONFIG_FW_CFG_SYSFS is not set
|
|
||||||
# CONFIG_ARM_FFA_TRANSPORT is not set
|
|
||||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# EFI (Extensible Firmware Interface) Support
|
|
||||||
#
|
|
||||||
CONFIG_EFI_ESRT=y
|
|
||||||
CONFIG_EFI_PARAMS_FROM_FDT=y
|
|
||||||
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
|
||||||
CONFIG_EFI_GENERIC_STUB=y
|
|
||||||
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
|
|
||||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
|
||||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
|
||||||
# end of EFI (Extensible Firmware Interface) Support
|
|
||||||
|
|
||||||
CONFIG_EFI_EARLYCON=y
|
|
||||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
|
||||||
CONFIG_ARM_PSCI_FW=y
|
|
||||||
# CONFIG_ARM_PSCI_CHECKER is not set
|
|
||||||
CONFIG_HAVE_ARM_SMCCC=y
|
|
||||||
CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
|
||||||
# CONFIG_ARM_SMCCC_SOC_ID is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# Tegra firmware driver
|
|
||||||
#
|
|
||||||
# end of Tegra firmware driver
|
|
||||||
# end of Firmware Drivers
|
|
||||||
|
|
||||||
CONFIG_ARCH_SUPPORTS_ACPI=y
|
CONFIG_ARCH_SUPPORTS_ACPI=y
|
||||||
CONFIG_ACPI=y
|
CONFIG_ACPI=y
|
||||||
CONFIG_ACPI_GENERIC_GSI=y
|
CONFIG_ACPI_GENERIC_GSI=y
|
||||||
@@ -640,6 +605,8 @@ CONFIG_HAVE_KVM_ARCH_TLB_FLUSH_ALL=y
|
|||||||
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=y
|
||||||
CONFIG_HAVE_KVM_IRQ_BYPASS=y
|
CONFIG_HAVE_KVM_IRQ_BYPASS=y
|
||||||
CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y
|
CONFIG_HAVE_KVM_VCPU_RUN_PID_CHANGE=y
|
||||||
|
CONFIG_KVM_XFER_TO_GUEST_WORK=y
|
||||||
|
# CONFIG_NVHE_EL2_DEBUG is not set
|
||||||
# CONFIG_ARM64_CRYPTO is not set
|
# CONFIG_ARM64_CRYPTO is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -654,6 +621,7 @@ CONFIG_HAVE_KPROBES=y
|
|||||||
CONFIG_HAVE_KRETPROBES=y
|
CONFIG_HAVE_KRETPROBES=y
|
||||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||||
CONFIG_HAVE_NMI=y
|
CONFIG_HAVE_NMI=y
|
||||||
|
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||||
@@ -738,15 +706,14 @@ CONFIG_BASE_SMALL=0
|
|||||||
# CONFIG_MODULES is not set
|
# CONFIG_MODULES is not set
|
||||||
CONFIG_MODULES_TREE_LOOKUP=y
|
CONFIG_MODULES_TREE_LOOKUP=y
|
||||||
CONFIG_BLOCK=y
|
CONFIG_BLOCK=y
|
||||||
CONFIG_BLK_SCSI_REQUEST=y
|
|
||||||
CONFIG_BLK_CGROUP_RWSTAT=y
|
CONFIG_BLK_CGROUP_RWSTAT=y
|
||||||
CONFIG_BLK_DEV_BSG=y
|
CONFIG_BLK_DEV_BSG_COMMON=y
|
||||||
CONFIG_BLK_DEV_BSGLIB=y
|
CONFIG_BLK_DEV_BSGLIB=y
|
||||||
CONFIG_BLK_DEV_INTEGRITY=y
|
CONFIG_BLK_DEV_INTEGRITY=y
|
||||||
|
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
||||||
# CONFIG_BLK_DEV_ZONED is not set
|
# CONFIG_BLK_DEV_ZONED is not set
|
||||||
CONFIG_BLK_DEV_THROTTLING=y
|
CONFIG_BLK_DEV_THROTTLING=y
|
||||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||||
CONFIG_BLK_CMDLINE_PARSER=y
|
|
||||||
CONFIG_BLK_WBT=y
|
CONFIG_BLK_WBT=y
|
||||||
CONFIG_BLK_WBT_MQ=y
|
CONFIG_BLK_WBT_MQ=y
|
||||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||||
@@ -936,11 +903,18 @@ CONFIG_ZONE_DMA32=y
|
|||||||
CONFIG_ZONE_DEVICE=y
|
CONFIG_ZONE_DEVICE=y
|
||||||
CONFIG_DEV_PAGEMAP_OPS=y
|
CONFIG_DEV_PAGEMAP_OPS=y
|
||||||
# CONFIG_DEVICE_PRIVATE is not set
|
# CONFIG_DEVICE_PRIVATE is not set
|
||||||
|
CONFIG_ARCH_USES_HIGH_VMA_FLAGS=y
|
||||||
CONFIG_PERCPU_STATS=y
|
CONFIG_PERCPU_STATS=y
|
||||||
# CONFIG_GUP_TEST is not set
|
# CONFIG_GUP_TEST is not set
|
||||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||||
CONFIG_SECRETMEM=y
|
CONFIG_SECRETMEM=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Data Access Monitoring
|
||||||
|
#
|
||||||
|
# CONFIG_DAMON is not set
|
||||||
|
# end of Data Access Monitoring
|
||||||
# end of Memory Management options
|
# end of Memory Management options
|
||||||
|
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
@@ -953,6 +927,7 @@ CONFIG_PACKET=y
|
|||||||
CONFIG_PACKET_DIAG=y
|
CONFIG_PACKET_DIAG=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
CONFIG_UNIX_SCM=y
|
CONFIG_UNIX_SCM=y
|
||||||
|
CONFIG_AF_UNIX_OOB=y
|
||||||
CONFIG_UNIX_DIAG=y
|
CONFIG_UNIX_DIAG=y
|
||||||
CONFIG_TLS=y
|
CONFIG_TLS=y
|
||||||
# CONFIG_TLS_DEVICE is not set
|
# CONFIG_TLS_DEVICE is not set
|
||||||
@@ -1056,6 +1031,7 @@ CONFIG_NET_FLOW_LIMIT=y
|
|||||||
# CONFIG_AF_RXRPC is not set
|
# CONFIG_AF_RXRPC is not set
|
||||||
# CONFIG_AF_KCM is not set
|
# CONFIG_AF_KCM is not set
|
||||||
CONFIG_STREAM_PARSER=y
|
CONFIG_STREAM_PARSER=y
|
||||||
|
# CONFIG_MCTP is not set
|
||||||
# CONFIG_WIRELESS is not set
|
# CONFIG_WIRELESS is not set
|
||||||
# CONFIG_RFKILL is not set
|
# CONFIG_RFKILL is not set
|
||||||
# CONFIG_NET_9P is not set
|
# CONFIG_NET_9P is not set
|
||||||
@@ -1202,13 +1178,64 @@ CONFIG_GENERIC_ARCH_NUMA=y
|
|||||||
# Bus devices
|
# Bus devices
|
||||||
#
|
#
|
||||||
# CONFIG_BRCMSTB_GISB_ARB is not set
|
# CONFIG_BRCMSTB_GISB_ARB is not set
|
||||||
# CONFIG_SIMPLE_PM_BUS is not set
|
|
||||||
# CONFIG_VEXPRESS_CONFIG is not set
|
# CONFIG_VEXPRESS_CONFIG is not set
|
||||||
# CONFIG_MHI_BUS is not set
|
# CONFIG_MHI_BUS is not set
|
||||||
# end of Bus devices
|
# end of Bus devices
|
||||||
|
|
||||||
CONFIG_CONNECTOR=y
|
CONFIG_CONNECTOR=y
|
||||||
CONFIG_PROC_EVENTS=y
|
CONFIG_PROC_EVENTS=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Firmware Drivers
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# ARM System Control and Management Interface Protocol
|
||||||
|
#
|
||||||
|
# CONFIG_ARM_SCMI_PROTOCOL is not set
|
||||||
|
# end of ARM System Control and Management Interface Protocol
|
||||||
|
|
||||||
|
# CONFIG_ARM_SCPI_PROTOCOL is not set
|
||||||
|
# CONFIG_ARM_SDE_INTERFACE is not set
|
||||||
|
CONFIG_FIRMWARE_MEMMAP=y
|
||||||
|
CONFIG_DMIID=y
|
||||||
|
CONFIG_DMI_SYSFS=y
|
||||||
|
# CONFIG_FW_CFG_SYSFS is not set
|
||||||
|
CONFIG_SYSFB=y
|
||||||
|
# CONFIG_SYSFB_SIMPLEFB is not set
|
||||||
|
# CONFIG_ARM_FFA_TRANSPORT is not set
|
||||||
|
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# EFI (Extensible Firmware Interface) Support
|
||||||
|
#
|
||||||
|
CONFIG_EFI_ESRT=y
|
||||||
|
CONFIG_EFI_PARAMS_FROM_FDT=y
|
||||||
|
CONFIG_EFI_RUNTIME_WRAPPERS=y
|
||||||
|
CONFIG_EFI_GENERIC_STUB=y
|
||||||
|
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
|
||||||
|
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||||
|
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||||
|
# end of EFI (Extensible Firmware Interface) Support
|
||||||
|
|
||||||
|
CONFIG_EFI_EARLYCON=y
|
||||||
|
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||||
|
CONFIG_ARM_PSCI_FW=y
|
||||||
|
# CONFIG_ARM_PSCI_CHECKER is not set
|
||||||
|
CONFIG_HAVE_ARM_SMCCC=y
|
||||||
|
CONFIG_HAVE_ARM_SMCCC_DISCOVERY=y
|
||||||
|
# CONFIG_ARM_SMCCC_SOC_ID is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tegra firmware driver
|
||||||
|
#
|
||||||
|
# end of Tegra firmware driver
|
||||||
|
# end of Firmware Drivers
|
||||||
|
|
||||||
# CONFIG_GNSS is not set
|
# CONFIG_GNSS is not set
|
||||||
# CONFIG_MTD is not set
|
# CONFIG_MTD is not set
|
||||||
CONFIG_DTC=y
|
CONFIG_DTC=y
|
||||||
@@ -1258,7 +1285,9 @@ CONFIG_VIRTIO_BLK=y
|
|||||||
#
|
#
|
||||||
# NVME Support
|
# NVME Support
|
||||||
#
|
#
|
||||||
# CONFIG_BLK_DEV_NVME is not set
|
CONFIG_NVME_CORE=y
|
||||||
|
CONFIG_BLK_DEV_NVME=y
|
||||||
|
CONFIG_NVME_MULTIPATH=y
|
||||||
# CONFIG_NVME_FC is not set
|
# CONFIG_NVME_FC is not set
|
||||||
# CONFIG_NVME_TCP is not set
|
# CONFIG_NVME_TCP is not set
|
||||||
# CONFIG_NVME_TARGET is not set
|
# CONFIG_NVME_TARGET is not set
|
||||||
@@ -1315,7 +1344,38 @@ CONFIG_SCSI_MOD=y
|
|||||||
|
|
||||||
CONFIG_HAVE_PATA_PLATFORM=y
|
CONFIG_HAVE_PATA_PLATFORM=y
|
||||||
# CONFIG_ATA is not set
|
# CONFIG_ATA is not set
|
||||||
# CONFIG_MD is not set
|
CONFIG_MD=y
|
||||||
|
# CONFIG_BLK_DEV_MD is not set
|
||||||
|
# CONFIG_BCACHE is not set
|
||||||
|
CONFIG_BLK_DEV_DM_BUILTIN=y
|
||||||
|
CONFIG_BLK_DEV_DM=y
|
||||||
|
# CONFIG_DM_DEBUG is not set
|
||||||
|
# CONFIG_DM_UNSTRIPED is not set
|
||||||
|
# CONFIG_DM_CRYPT is not set
|
||||||
|
# CONFIG_DM_SNAPSHOT is not set
|
||||||
|
# CONFIG_DM_THIN_PROVISIONING is not set
|
||||||
|
# CONFIG_DM_CACHE is not set
|
||||||
|
# CONFIG_DM_WRITECACHE is not set
|
||||||
|
# CONFIG_DM_EBS is not set
|
||||||
|
# CONFIG_DM_ERA is not set
|
||||||
|
# CONFIG_DM_CLONE is not set
|
||||||
|
# CONFIG_DM_MIRROR is not set
|
||||||
|
# CONFIG_DM_RAID is not set
|
||||||
|
# CONFIG_DM_ZERO is not set
|
||||||
|
CONFIG_DM_MULTIPATH=y
|
||||||
|
# CONFIG_DM_MULTIPATH_QL is not set
|
||||||
|
# CONFIG_DM_MULTIPATH_ST is not set
|
||||||
|
# CONFIG_DM_MULTIPATH_HST is not set
|
||||||
|
# CONFIG_DM_MULTIPATH_IOA is not set
|
||||||
|
# CONFIG_DM_DELAY is not set
|
||||||
|
# CONFIG_DM_DUST is not set
|
||||||
|
# CONFIG_DM_INIT is not set
|
||||||
|
# CONFIG_DM_UEVENT is not set
|
||||||
|
# CONFIG_DM_FLAKEY is not set
|
||||||
|
# CONFIG_DM_VERITY is not set
|
||||||
|
# CONFIG_DM_SWITCH is not set
|
||||||
|
# CONFIG_DM_LOG_WRITES is not set
|
||||||
|
# CONFIG_DM_INTEGRITY is not set
|
||||||
# CONFIG_TARGET_CORE is not set
|
# CONFIG_TARGET_CORE is not set
|
||||||
# CONFIG_FUSION is not set
|
# CONFIG_FUSION is not set
|
||||||
|
|
||||||
@@ -1379,7 +1439,6 @@ CONFIG_VIRTIO_NET=y
|
|||||||
# CONFIG_NETDEVSIM is not set
|
# CONFIG_NETDEVSIM is not set
|
||||||
CONFIG_NET_FAILOVER=y
|
CONFIG_NET_FAILOVER=y
|
||||||
# CONFIG_ISDN is not set
|
# CONFIG_ISDN is not set
|
||||||
# CONFIG_NVM is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Input device support
|
# Input device support
|
||||||
@@ -1523,15 +1582,15 @@ CONFIG_HW_RANDOM_VIRTIO=y
|
|||||||
CONFIG_HW_RANDOM_CAVIUM=y
|
CONFIG_HW_RANDOM_CAVIUM=y
|
||||||
# CONFIG_HW_RANDOM_CCTRNG is not set
|
# CONFIG_HW_RANDOM_CCTRNG is not set
|
||||||
# CONFIG_HW_RANDOM_XIPHERA is not set
|
# CONFIG_HW_RANDOM_XIPHERA is not set
|
||||||
|
CONFIG_HW_RANDOM_ARM_SMCCC_TRNG=y
|
||||||
# CONFIG_APPLICOM is not set
|
# CONFIG_APPLICOM is not set
|
||||||
CONFIG_DEVMEM=y
|
CONFIG_DEVMEM=y
|
||||||
CONFIG_DEVPORT=y
|
CONFIG_DEVPORT=y
|
||||||
# CONFIG_TCG_TPM is not set
|
# CONFIG_TCG_TPM is not set
|
||||||
# CONFIG_XILLYBUS is not set
|
# CONFIG_XILLYBUS is not set
|
||||||
# end of Character devices
|
|
||||||
|
|
||||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||||
|
# end of Character devices
|
||||||
|
|
||||||
#
|
#
|
||||||
# I2C support
|
# I2C support
|
||||||
@@ -1561,12 +1620,12 @@ CONFIG_PPS_CLIENT_GPIO=y
|
|||||||
# PTP clock support
|
# PTP clock support
|
||||||
#
|
#
|
||||||
CONFIG_PTP_1588_CLOCK=y
|
CONFIG_PTP_1588_CLOCK=y
|
||||||
|
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
||||||
#
|
#
|
||||||
CONFIG_PTP_1588_CLOCK_KVM=y
|
CONFIG_PTP_1588_CLOCK_KVM=y
|
||||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
|
||||||
# end of PTP clock support
|
# end of PTP clock support
|
||||||
|
|
||||||
# CONFIG_PINCTRL is not set
|
# CONFIG_PINCTRL is not set
|
||||||
@@ -1620,6 +1679,7 @@ CONFIG_GPIO_PL061=y
|
|||||||
#
|
#
|
||||||
# CONFIG_GPIO_AGGREGATOR is not set
|
# CONFIG_GPIO_AGGREGATOR is not set
|
||||||
# CONFIG_GPIO_MOCKUP is not set
|
# CONFIG_GPIO_MOCKUP is not set
|
||||||
|
# CONFIG_GPIO_VIRTIO is not set
|
||||||
# end of Virtual GPIO drivers
|
# end of Virtual GPIO drivers
|
||||||
|
|
||||||
# CONFIG_W1 is not set
|
# CONFIG_W1 is not set
|
||||||
@@ -1838,7 +1898,6 @@ CONFIG_HID_GENERIC=y
|
|||||||
# CONFIG_HID_AUREAL is not set
|
# CONFIG_HID_AUREAL is not set
|
||||||
# CONFIG_HID_BELKIN is not set
|
# CONFIG_HID_BELKIN is not set
|
||||||
# CONFIG_HID_CHERRY is not set
|
# CONFIG_HID_CHERRY is not set
|
||||||
# CONFIG_HID_CHICONY is not set
|
|
||||||
# CONFIG_HID_COUGAR is not set
|
# CONFIG_HID_COUGAR is not set
|
||||||
# CONFIG_HID_MACALLY is not set
|
# CONFIG_HID_MACALLY is not set
|
||||||
# CONFIG_HID_CMEDIA is not set
|
# CONFIG_HID_CMEDIA is not set
|
||||||
@@ -1879,7 +1938,6 @@ CONFIG_HID_REDRAGON=y
|
|||||||
# CONFIG_HID_PLAYSTATION is not set
|
# CONFIG_HID_PLAYSTATION is not set
|
||||||
# CONFIG_HID_PRIMAX is not set
|
# CONFIG_HID_PRIMAX is not set
|
||||||
# CONFIG_HID_SAITEK is not set
|
# CONFIG_HID_SAITEK is not set
|
||||||
# CONFIG_HID_SAMSUNG is not set
|
|
||||||
# CONFIG_HID_SEMITEK is not set
|
# CONFIG_HID_SEMITEK is not set
|
||||||
# CONFIG_HID_SPEEDLINK is not set
|
# CONFIG_HID_SPEEDLINK is not set
|
||||||
# CONFIG_HID_STEAM is not set
|
# CONFIG_HID_STEAM is not set
|
||||||
@@ -2011,8 +2069,6 @@ CONFIG_DMA_OF=y
|
|||||||
# DMABUF options
|
# DMABUF options
|
||||||
#
|
#
|
||||||
# CONFIG_SYNC_FILE is not set
|
# CONFIG_SYNC_FILE is not set
|
||||||
# CONFIG_DMABUF_MOVE_NOTIFY is not set
|
|
||||||
# CONFIG_DMABUF_DEBUG is not set
|
|
||||||
# CONFIG_DMABUF_HEAPS is not set
|
# CONFIG_DMABUF_HEAPS is not set
|
||||||
# end of DMABUF options
|
# end of DMABUF options
|
||||||
|
|
||||||
@@ -2027,13 +2083,14 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
|||||||
# CONFIG_UIO_NETX is not set
|
# CONFIG_UIO_NETX is not set
|
||||||
# CONFIG_UIO_PRUSS is not set
|
# CONFIG_UIO_PRUSS is not set
|
||||||
# CONFIG_UIO_MF624 is not set
|
# CONFIG_UIO_MF624 is not set
|
||||||
|
CONFIG_VFIO=y
|
||||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||||
CONFIG_VFIO_VIRQFD=y
|
CONFIG_VFIO_VIRQFD=y
|
||||||
CONFIG_VFIO=y
|
|
||||||
# CONFIG_VFIO_NOIOMMU is not set
|
# CONFIG_VFIO_NOIOMMU is not set
|
||||||
CONFIG_VFIO_PCI=y
|
CONFIG_VFIO_PCI_CORE=y
|
||||||
CONFIG_VFIO_PCI_MMAP=y
|
CONFIG_VFIO_PCI_MMAP=y
|
||||||
CONFIG_VFIO_PCI_INTX=y
|
CONFIG_VFIO_PCI_INTX=y
|
||||||
|
CONFIG_VFIO_PCI=y
|
||||||
# CONFIG_VFIO_PLATFORM is not set
|
# CONFIG_VFIO_PLATFORM is not set
|
||||||
# CONFIG_VFIO_MDEV is not set
|
# CONFIG_VFIO_MDEV is not set
|
||||||
# CONFIG_VIRT_DRIVERS is not set
|
# CONFIG_VIRT_DRIVERS is not set
|
||||||
@@ -2057,6 +2114,7 @@ CONFIG_VHOST_MENU=y
|
|||||||
#
|
#
|
||||||
# Microsoft Hyper-V guest support
|
# Microsoft Hyper-V guest support
|
||||||
#
|
#
|
||||||
|
# CONFIG_HYPERV is not set
|
||||||
# end of Microsoft Hyper-V guest support
|
# end of Microsoft Hyper-V guest support
|
||||||
|
|
||||||
# CONFIG_GREYBUS is not set
|
# CONFIG_GREYBUS is not set
|
||||||
@@ -2118,6 +2176,8 @@ CONFIG_IOMMU_SUPPORT=y
|
|||||||
# end of Generic IOMMU Pagetable Support
|
# end of Generic IOMMU Pagetable Support
|
||||||
|
|
||||||
# CONFIG_IOMMU_DEBUGFS is not set
|
# CONFIG_IOMMU_DEBUGFS is not set
|
||||||
|
CONFIG_IOMMU_DEFAULT_DMA_STRICT=y
|
||||||
|
# CONFIG_IOMMU_DEFAULT_DMA_LAZY is not set
|
||||||
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
||||||
CONFIG_OF_IOMMU=y
|
CONFIG_OF_IOMMU=y
|
||||||
CONFIG_IOMMU_DMA=y
|
CONFIG_IOMMU_DMA=y
|
||||||
@@ -2320,7 +2380,6 @@ CONFIG_FS_POSIX_ACL=y
|
|||||||
CONFIG_EXPORTFS=y
|
CONFIG_EXPORTFS=y
|
||||||
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
||||||
CONFIG_FILE_LOCKING=y
|
CONFIG_FILE_LOCKING=y
|
||||||
CONFIG_MANDATORY_FILE_LOCKING=y
|
|
||||||
CONFIG_FS_ENCRYPTION=y
|
CONFIG_FS_ENCRYPTION=y
|
||||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||||
# CONFIG_FS_VERITY is not set
|
# CONFIG_FS_VERITY is not set
|
||||||
@@ -2349,12 +2408,9 @@ CONFIG_NETFS_SUPPORT=y
|
|||||||
# CONFIG_NETFS_STATS is not set
|
# CONFIG_NETFS_STATS is not set
|
||||||
CONFIG_FSCACHE=y
|
CONFIG_FSCACHE=y
|
||||||
# CONFIG_FSCACHE_STATS is not set
|
# CONFIG_FSCACHE_STATS is not set
|
||||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
|
||||||
# CONFIG_FSCACHE_DEBUG is not set
|
# CONFIG_FSCACHE_DEBUG is not set
|
||||||
# CONFIG_FSCACHE_OBJECT_LIST is not set
|
|
||||||
CONFIG_CACHEFILES=y
|
CONFIG_CACHEFILES=y
|
||||||
# CONFIG_CACHEFILES_DEBUG is not set
|
# CONFIG_CACHEFILES_DEBUG is not set
|
||||||
# CONFIG_CACHEFILES_HISTOGRAM is not set
|
|
||||||
# end of Caches
|
# end of Caches
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -2375,6 +2431,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
|
|||||||
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
||||||
# CONFIG_EXFAT_FS is not set
|
# CONFIG_EXFAT_FS is not set
|
||||||
# CONFIG_NTFS_FS is not set
|
# CONFIG_NTFS_FS is not set
|
||||||
|
# CONFIG_NTFS3_FS is not set
|
||||||
# end of DOS/FAT/EXFAT/NT Filesystems
|
# end of DOS/FAT/EXFAT/NT Filesystems
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -2772,6 +2829,7 @@ CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE=y
|
|||||||
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU=y
|
||||||
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
|
CONFIG_ARCH_HAS_DMA_PREP_COHERENT=y
|
||||||
CONFIG_SWIOTLB=y
|
CONFIG_SWIOTLB=y
|
||||||
|
# CONFIG_DMA_RESTRICTED_POOL is not set
|
||||||
CONFIG_DMA_NONCOHERENT_MMAP=y
|
CONFIG_DMA_NONCOHERENT_MMAP=y
|
||||||
CONFIG_DMA_COHERENT_POOL=y
|
CONFIG_DMA_COHERENT_POOL=y
|
||||||
CONFIG_DMA_REMAP=y
|
CONFIG_DMA_REMAP=y
|
||||||
@@ -2884,8 +2942,11 @@ CONFIG_DEBUG_MEMORY_INIT=y
|
|||||||
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
# CONFIG_DEBUG_PER_CPU_MAPS is not set
|
||||||
CONFIG_HAVE_ARCH_KASAN=y
|
CONFIG_HAVE_ARCH_KASAN=y
|
||||||
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
CONFIG_HAVE_ARCH_KASAN_SW_TAGS=y
|
||||||
|
CONFIG_HAVE_ARCH_KASAN_HW_TAGS=y
|
||||||
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
|
CONFIG_HAVE_ARCH_KASAN_VMALLOC=y
|
||||||
CONFIG_CC_HAS_KASAN_GENERIC=y
|
CONFIG_CC_HAS_KASAN_GENERIC=y
|
||||||
|
CONFIG_CC_HAS_WORKING_NOSANITIZE_ADDRESS=y
|
||||||
|
# CONFIG_KASAN is not set
|
||||||
CONFIG_HAVE_ARCH_KFENCE=y
|
CONFIG_HAVE_ARCH_KFENCE=y
|
||||||
# CONFIG_KFENCE is not set
|
# CONFIG_KFENCE is not set
|
||||||
# end of Memory Debugging
|
# end of Memory Debugging
|
||||||
@@ -2962,12 +3023,12 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=59
|
|||||||
# end of RCU Debugging
|
# end of RCU Debugging
|
||||||
|
|
||||||
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
||||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
|
||||||
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
||||||
# CONFIG_LATENCYTOP is not set
|
# CONFIG_LATENCYTOP is not set
|
||||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||||
|
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
|
||||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||||
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||||
@@ -2996,7 +3057,6 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
|||||||
CONFIG_RUNTIME_TESTING_MENU=y
|
CONFIG_RUNTIME_TESTING_MENU=y
|
||||||
# CONFIG_LKDTM is not set
|
# CONFIG_LKDTM is not set
|
||||||
# CONFIG_TEST_MIN_HEAP is not set
|
# CONFIG_TEST_MIN_HEAP is not set
|
||||||
# CONFIG_TEST_SORT is not set
|
|
||||||
# CONFIG_TEST_DIV64 is not set
|
# CONFIG_TEST_DIV64 is not set
|
||||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||||
# CONFIG_RBTREE_TEST is not set
|
# CONFIG_RBTREE_TEST is not set
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#
|
#
|
||||||
# Automatically generated file; DO NOT EDIT.
|
# Automatically generated file; DO NOT EDIT.
|
||||||
# Linux/x86 5.14.0 Kernel Configuration
|
# Linux/x86 5.15.12 Kernel Configuration
|
||||||
#
|
#
|
||||||
CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 10.3.0-1ubuntu1) 10.3.0"
|
CONFIG_CC_VERSION_TEXT="gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7)"
|
||||||
CONFIG_CC_IS_GCC=y
|
CONFIG_CC_IS_GCC=y
|
||||||
CONFIG_GCC_VERSION=100300
|
CONFIG_GCC_VERSION=110201
|
||||||
CONFIG_CLANG_VERSION=0
|
CONFIG_CLANG_VERSION=0
|
||||||
CONFIG_AS_IS_GNU=y
|
CONFIG_AS_IS_GNU=y
|
||||||
CONFIG_AS_VERSION=23500
|
CONFIG_AS_VERSION=23700
|
||||||
CONFIG_LD_IS_BFD=y
|
CONFIG_LD_IS_BFD=y
|
||||||
CONFIG_LD_VERSION=23500
|
CONFIG_LD_VERSION=23700
|
||||||
CONFIG_LLD_VERSION=0
|
CONFIG_LLD_VERSION=0
|
||||||
CONFIG_CC_CAN_LINK=y
|
CONFIG_CC_CAN_LINK=y
|
||||||
CONFIG_CC_CAN_LINK_STATIC=y
|
|
||||||
CONFIG_CC_HAS_ASM_GOTO=y
|
CONFIG_CC_HAS_ASM_GOTO=y
|
||||||
|
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||||
CONFIG_CC_HAS_ASM_INLINE=y
|
CONFIG_CC_HAS_ASM_INLINE=y
|
||||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||||
CONFIG_IRQ_WORK=y
|
CONFIG_IRQ_WORK=y
|
||||||
@@ -25,6 +25,7 @@ CONFIG_THREAD_INFO_IN_TASK=y
|
|||||||
#
|
#
|
||||||
CONFIG_INIT_ENV_ARG_LIMIT=32
|
CONFIG_INIT_ENV_ARG_LIMIT=32
|
||||||
# CONFIG_COMPILE_TEST is not set
|
# CONFIG_COMPILE_TEST is not set
|
||||||
|
# CONFIG_WERROR is not set
|
||||||
CONFIG_LOCALVERSION=""
|
CONFIG_LOCALVERSION=""
|
||||||
# CONFIG_LOCALVERSION_AUTO is not set
|
# CONFIG_LOCALVERSION_AUTO is not set
|
||||||
CONFIG_BUILD_SALT=""
|
CONFIG_BUILD_SALT=""
|
||||||
@@ -154,6 +155,7 @@ CONFIG_BUILD_BIN2C=y
|
|||||||
CONFIG_LOG_BUF_SHIFT=21
|
CONFIG_LOG_BUF_SHIFT=21
|
||||||
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
|
||||||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=13
|
||||||
|
# CONFIG_PRINTK_INDEX is not set
|
||||||
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
|
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -226,7 +228,6 @@ CONFIG_SYSFS_SYSCALL=y
|
|||||||
CONFIG_FHANDLE=y
|
CONFIG_FHANDLE=y
|
||||||
CONFIG_POSIX_TIMERS=y
|
CONFIG_POSIX_TIMERS=y
|
||||||
CONFIG_PRINTK=y
|
CONFIG_PRINTK=y
|
||||||
CONFIG_PRINTK_NMI=y
|
|
||||||
CONFIG_BUG=y
|
CONFIG_BUG=y
|
||||||
CONFIG_ELF_CORE=y
|
CONFIG_ELF_CORE=y
|
||||||
CONFIG_PCSPKR_PLATFORM=y
|
CONFIG_PCSPKR_PLATFORM=y
|
||||||
@@ -299,6 +300,7 @@ CONFIG_HAVE_SETUP_PER_CPU_AREA=y
|
|||||||
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
||||||
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
|
CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
|
||||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||||
|
CONFIG_ARCH_NR_GPIO=1024
|
||||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||||
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
|
||||||
CONFIG_AUDIT_ARCH=y
|
CONFIG_AUDIT_ARCH=y
|
||||||
@@ -380,13 +382,13 @@ CONFIG_PERF_EVENTS_INTEL_UNCORE=y
|
|||||||
CONFIG_PERF_EVENTS_INTEL_RAPL=y
|
CONFIG_PERF_EVENTS_INTEL_RAPL=y
|
||||||
CONFIG_PERF_EVENTS_INTEL_CSTATE=y
|
CONFIG_PERF_EVENTS_INTEL_CSTATE=y
|
||||||
# CONFIG_PERF_EVENTS_AMD_POWER is not set
|
# CONFIG_PERF_EVENTS_AMD_POWER is not set
|
||||||
|
CONFIG_PERF_EVENTS_AMD_UNCORE=y
|
||||||
# end of Performance monitoring
|
# end of Performance monitoring
|
||||||
|
|
||||||
CONFIG_X86_16BIT=y
|
CONFIG_X86_16BIT=y
|
||||||
CONFIG_X86_ESPFIX64=y
|
CONFIG_X86_ESPFIX64=y
|
||||||
CONFIG_X86_VSYSCALL_EMULATION=y
|
CONFIG_X86_VSYSCALL_EMULATION=y
|
||||||
# CONFIG_X86_IOPL_IOPERM is not set
|
# CONFIG_X86_IOPL_IOPERM is not set
|
||||||
# CONFIG_I8K is not set
|
|
||||||
# CONFIG_MICROCODE is not set
|
# CONFIG_MICROCODE is not set
|
||||||
CONFIG_X86_MSR=y
|
CONFIG_X86_MSR=y
|
||||||
CONFIG_X86_CPUID=y
|
CONFIG_X86_CPUID=y
|
||||||
@@ -585,7 +587,6 @@ CONFIG_MMCONF_FAM10H=y
|
|||||||
# CONFIG_ISA_BUS is not set
|
# CONFIG_ISA_BUS is not set
|
||||||
# CONFIG_ISA_DMA_API is not set
|
# CONFIG_ISA_DMA_API is not set
|
||||||
CONFIG_AMD_NB=y
|
CONFIG_AMD_NB=y
|
||||||
# CONFIG_X86_SYSFB is not set
|
|
||||||
# end of Bus options (PCI etc.)
|
# end of Bus options (PCI etc.)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -595,44 +596,6 @@ CONFIG_AMD_NB=y
|
|||||||
# CONFIG_X86_X32 is not set
|
# CONFIG_X86_X32 is not set
|
||||||
# end of Binary Emulations
|
# end of Binary Emulations
|
||||||
|
|
||||||
#
|
|
||||||
# Firmware Drivers
|
|
||||||
#
|
|
||||||
# CONFIG_EDD is not set
|
|
||||||
CONFIG_FIRMWARE_MEMMAP=y
|
|
||||||
CONFIG_DMIID=y
|
|
||||||
CONFIG_DMI_SYSFS=y
|
|
||||||
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
|
|
||||||
# CONFIG_FW_CFG_SYSFS is not set
|
|
||||||
# CONFIG_GOOGLE_FIRMWARE is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# EFI (Extensible Firmware Interface) Support
|
|
||||||
#
|
|
||||||
# CONFIG_EFI_VARS is not set
|
|
||||||
CONFIG_EFI_ESRT=y
|
|
||||||
CONFIG_EFI_RUNTIME_MAP=y
|
|
||||||
# CONFIG_EFI_FAKE_MEMMAP is not set
|
|
||||||
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
|
|
||||||
# CONFIG_APPLE_PROPERTIES is not set
|
|
||||||
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
|
||||||
# CONFIG_EFI_RCI2_TABLE is not set
|
|
||||||
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
|
||||||
# end of EFI (Extensible Firmware Interface) Support
|
|
||||||
|
|
||||||
CONFIG_EFI_EARLYCON=y
|
|
||||||
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
|
||||||
|
|
||||||
#
|
|
||||||
# Tegra firmware driver
|
|
||||||
#
|
|
||||||
# end of Tegra firmware driver
|
|
||||||
# end of Firmware Drivers
|
|
||||||
|
|
||||||
CONFIG_HAVE_KVM=y
|
CONFIG_HAVE_KVM=y
|
||||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||||
CONFIG_HAVE_KVM_IRQFD=y
|
CONFIG_HAVE_KVM_IRQFD=y
|
||||||
@@ -679,6 +642,7 @@ CONFIG_HAVE_OPTPROBES=y
|
|||||||
CONFIG_HAVE_KPROBES_ON_FTRACE=y
|
CONFIG_HAVE_KPROBES_ON_FTRACE=y
|
||||||
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
CONFIG_HAVE_FUNCTION_ERROR_INJECTION=y
|
||||||
CONFIG_HAVE_NMI=y
|
CONFIG_HAVE_NMI=y
|
||||||
|
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
||||||
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||||
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||||
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||||
@@ -753,12 +717,14 @@ CONFIG_HAVE_ARCH_PREL32_RELOCATIONS=y
|
|||||||
CONFIG_ARCH_USE_MEMREMAP_PROT=y
|
CONFIG_ARCH_USE_MEMREMAP_PROT=y
|
||||||
# CONFIG_LOCK_EVENT_COUNTS is not set
|
# CONFIG_LOCK_EVENT_COUNTS is not set
|
||||||
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
|
CONFIG_ARCH_HAS_MEM_ENCRYPT=y
|
||||||
|
CONFIG_ARCH_HAS_CC_PLATFORM=y
|
||||||
CONFIG_HAVE_STATIC_CALL=y
|
CONFIG_HAVE_STATIC_CALL=y
|
||||||
CONFIG_HAVE_STATIC_CALL_INLINE=y
|
CONFIG_HAVE_STATIC_CALL_INLINE=y
|
||||||
CONFIG_HAVE_PREEMPT_DYNAMIC=y
|
CONFIG_HAVE_PREEMPT_DYNAMIC=y
|
||||||
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
|
CONFIG_ARCH_WANT_LD_ORPHAN_WARN=y
|
||||||
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
|
||||||
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
|
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
|
||||||
|
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# GCOV-based kernel profiling
|
# GCOV-based kernel profiling
|
||||||
@@ -775,16 +741,14 @@ CONFIG_BASE_SMALL=0
|
|||||||
# CONFIG_MODULES is not set
|
# CONFIG_MODULES is not set
|
||||||
CONFIG_MODULES_TREE_LOOKUP=y
|
CONFIG_MODULES_TREE_LOOKUP=y
|
||||||
CONFIG_BLOCK=y
|
CONFIG_BLOCK=y
|
||||||
CONFIG_BLK_SCSI_REQUEST=y
|
|
||||||
CONFIG_BLK_CGROUP_RWSTAT=y
|
CONFIG_BLK_CGROUP_RWSTAT=y
|
||||||
CONFIG_BLK_DEV_BSG=y
|
CONFIG_BLK_DEV_BSG_COMMON=y
|
||||||
CONFIG_BLK_DEV_BSGLIB=y
|
CONFIG_BLK_DEV_BSGLIB=y
|
||||||
CONFIG_BLK_DEV_INTEGRITY=y
|
CONFIG_BLK_DEV_INTEGRITY=y
|
||||||
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
CONFIG_BLK_DEV_INTEGRITY_T10=y
|
||||||
# CONFIG_BLK_DEV_ZONED is not set
|
# CONFIG_BLK_DEV_ZONED is not set
|
||||||
CONFIG_BLK_DEV_THROTTLING=y
|
CONFIG_BLK_DEV_THROTTLING=y
|
||||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||||
CONFIG_BLK_CMDLINE_PARSER=y
|
|
||||||
CONFIG_BLK_WBT=y
|
CONFIG_BLK_WBT=y
|
||||||
CONFIG_BLK_WBT_MQ=y
|
CONFIG_BLK_WBT_MQ=y
|
||||||
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
# CONFIG_BLK_CGROUP_IOLATENCY is not set
|
||||||
@@ -818,6 +782,7 @@ CONFIG_EFI_PARTITION=y
|
|||||||
CONFIG_BLK_MQ_PCI=y
|
CONFIG_BLK_MQ_PCI=y
|
||||||
CONFIG_BLK_MQ_VIRTIO=y
|
CONFIG_BLK_MQ_VIRTIO=y
|
||||||
CONFIG_BLK_PM=y
|
CONFIG_BLK_PM=y
|
||||||
|
CONFIG_BLOCK_HOLDER_DEPRECATED=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# IO Schedulers
|
# IO Schedulers
|
||||||
@@ -934,6 +899,12 @@ CONFIG_PERCPU_STATS=y
|
|||||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||||
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
CONFIG_ARCH_HAS_PTE_SPECIAL=y
|
||||||
CONFIG_SECRETMEM=y
|
CONFIG_SECRETMEM=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Data Access Monitoring
|
||||||
|
#
|
||||||
|
# CONFIG_DAMON is not set
|
||||||
|
# end of Data Access Monitoring
|
||||||
# end of Memory Management options
|
# end of Memory Management options
|
||||||
|
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
@@ -946,6 +917,7 @@ CONFIG_PACKET=y
|
|||||||
CONFIG_PACKET_DIAG=y
|
CONFIG_PACKET_DIAG=y
|
||||||
CONFIG_UNIX=y
|
CONFIG_UNIX=y
|
||||||
CONFIG_UNIX_SCM=y
|
CONFIG_UNIX_SCM=y
|
||||||
|
CONFIG_AF_UNIX_OOB=y
|
||||||
CONFIG_UNIX_DIAG=y
|
CONFIG_UNIX_DIAG=y
|
||||||
CONFIG_TLS=y
|
CONFIG_TLS=y
|
||||||
# CONFIG_TLS_DEVICE is not set
|
# CONFIG_TLS_DEVICE is not set
|
||||||
@@ -1050,6 +1022,7 @@ CONFIG_NET_FLOW_LIMIT=y
|
|||||||
# CONFIG_AF_RXRPC is not set
|
# CONFIG_AF_RXRPC is not set
|
||||||
# CONFIG_AF_KCM is not set
|
# CONFIG_AF_KCM is not set
|
||||||
CONFIG_STREAM_PARSER=y
|
CONFIG_STREAM_PARSER=y
|
||||||
|
# CONFIG_MCTP is not set
|
||||||
# CONFIG_WIRELESS is not set
|
# CONFIG_WIRELESS is not set
|
||||||
# CONFIG_RFKILL is not set
|
# CONFIG_RFKILL is not set
|
||||||
# CONFIG_NET_9P is not set
|
# CONFIG_NET_9P is not set
|
||||||
@@ -1186,6 +1159,53 @@ CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
|||||||
|
|
||||||
CONFIG_CONNECTOR=y
|
CONFIG_CONNECTOR=y
|
||||||
CONFIG_PROC_EVENTS=y
|
CONFIG_PROC_EVENTS=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Firmware Drivers
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# ARM System Control and Management Interface Protocol
|
||||||
|
#
|
||||||
|
# end of ARM System Control and Management Interface Protocol
|
||||||
|
|
||||||
|
# CONFIG_EDD is not set
|
||||||
|
CONFIG_FIRMWARE_MEMMAP=y
|
||||||
|
CONFIG_DMIID=y
|
||||||
|
CONFIG_DMI_SYSFS=y
|
||||||
|
CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK=y
|
||||||
|
# CONFIG_FW_CFG_SYSFS is not set
|
||||||
|
CONFIG_SYSFB=y
|
||||||
|
# CONFIG_SYSFB_SIMPLEFB is not set
|
||||||
|
# CONFIG_GOOGLE_FIRMWARE is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# EFI (Extensible Firmware Interface) Support
|
||||||
|
#
|
||||||
|
# CONFIG_EFI_VARS is not set
|
||||||
|
CONFIG_EFI_ESRT=y
|
||||||
|
CONFIG_EFI_RUNTIME_MAP=y
|
||||||
|
# CONFIG_EFI_FAKE_MEMMAP is not set
|
||||||
|
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
|
||||||
|
# CONFIG_APPLE_PROPERTIES is not set
|
||||||
|
# CONFIG_RESET_ATTACK_MITIGATION is not set
|
||||||
|
# CONFIG_EFI_RCI2_TABLE is not set
|
||||||
|
# CONFIG_EFI_DISABLE_PCI_DMA is not set
|
||||||
|
# end of EFI (Extensible Firmware Interface) Support
|
||||||
|
|
||||||
|
CONFIG_EFI_EARLYCON=y
|
||||||
|
# CONFIG_EFI_CUSTOM_SSDT_OVERLAYS is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Tegra firmware driver
|
||||||
|
#
|
||||||
|
# end of Tegra firmware driver
|
||||||
|
# end of Firmware Drivers
|
||||||
|
|
||||||
# CONFIG_GNSS is not set
|
# CONFIG_GNSS is not set
|
||||||
# CONFIG_MTD is not set
|
# CONFIG_MTD is not set
|
||||||
# CONFIG_OF is not set
|
# CONFIG_OF is not set
|
||||||
@@ -1385,7 +1405,6 @@ CONFIG_VIRTIO_NET=y
|
|||||||
# CONFIG_NETDEVSIM is not set
|
# CONFIG_NETDEVSIM is not set
|
||||||
CONFIG_NET_FAILOVER=y
|
CONFIG_NET_FAILOVER=y
|
||||||
# CONFIG_ISDN is not set
|
# CONFIG_ISDN is not set
|
||||||
# CONFIG_NVM is not set
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Input device support
|
# Input device support
|
||||||
@@ -1534,10 +1553,9 @@ CONFIG_HANGCHECK_TIMER=y
|
|||||||
# CONFIG_TCG_TPM is not set
|
# CONFIG_TCG_TPM is not set
|
||||||
# CONFIG_TELCLOCK is not set
|
# CONFIG_TELCLOCK is not set
|
||||||
# CONFIG_XILLYBUS is not set
|
# CONFIG_XILLYBUS is not set
|
||||||
# end of Character devices
|
|
||||||
|
|
||||||
# CONFIG_RANDOM_TRUST_CPU is not set
|
# CONFIG_RANDOM_TRUST_CPU is not set
|
||||||
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
# CONFIG_RANDOM_TRUST_BOOTLOADER is not set
|
||||||
|
# end of Character devices
|
||||||
|
|
||||||
#
|
#
|
||||||
# I2C support
|
# I2C support
|
||||||
@@ -1567,13 +1585,13 @@ CONFIG_PPS=y
|
|||||||
# PTP clock support
|
# PTP clock support
|
||||||
#
|
#
|
||||||
CONFIG_PTP_1588_CLOCK=y
|
CONFIG_PTP_1588_CLOCK=y
|
||||||
|
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
|
||||||
#
|
#
|
||||||
CONFIG_PTP_1588_CLOCK_KVM=y
|
CONFIG_PTP_1588_CLOCK_KVM=y
|
||||||
# CONFIG_PTP_1588_CLOCK_VMW is not set
|
# CONFIG_PTP_1588_CLOCK_VMW is not set
|
||||||
# CONFIG_PTP_1588_CLOCK_OCP is not set
|
|
||||||
# end of PTP clock support
|
# end of PTP clock support
|
||||||
|
|
||||||
# CONFIG_PINCTRL is not set
|
# CONFIG_PINCTRL is not set
|
||||||
@@ -1629,6 +1647,7 @@ CONFIG_GPIO_PCI_IDIO_16=y
|
|||||||
#
|
#
|
||||||
# CONFIG_GPIO_AGGREGATOR is not set
|
# CONFIG_GPIO_AGGREGATOR is not set
|
||||||
# CONFIG_GPIO_MOCKUP is not set
|
# CONFIG_GPIO_MOCKUP is not set
|
||||||
|
# CONFIG_GPIO_VIRTIO is not set
|
||||||
# end of Virtual GPIO drivers
|
# end of Virtual GPIO drivers
|
||||||
|
|
||||||
# CONFIG_W1 is not set
|
# CONFIG_W1 is not set
|
||||||
@@ -1665,6 +1684,7 @@ CONFIG_X86_THERMAL_VECTOR=y
|
|||||||
|
|
||||||
# CONFIG_INTEL_PCH_THERMAL is not set
|
# CONFIG_INTEL_PCH_THERMAL is not set
|
||||||
# CONFIG_INTEL_TCC_COOLING is not set
|
# CONFIG_INTEL_TCC_COOLING is not set
|
||||||
|
# CONFIG_INTEL_MENLOW is not set
|
||||||
# end of Intel thermal drivers
|
# end of Intel thermal drivers
|
||||||
|
|
||||||
CONFIG_WATCHDOG=y
|
CONFIG_WATCHDOG=y
|
||||||
@@ -1884,7 +1904,6 @@ CONFIG_HID_GENERIC=y
|
|||||||
# CONFIG_HID_AUREAL is not set
|
# CONFIG_HID_AUREAL is not set
|
||||||
# CONFIG_HID_BELKIN is not set
|
# CONFIG_HID_BELKIN is not set
|
||||||
# CONFIG_HID_CHERRY is not set
|
# CONFIG_HID_CHERRY is not set
|
||||||
# CONFIG_HID_CHICONY is not set
|
|
||||||
# CONFIG_HID_COUGAR is not set
|
# CONFIG_HID_COUGAR is not set
|
||||||
# CONFIG_HID_MACALLY is not set
|
# CONFIG_HID_MACALLY is not set
|
||||||
# CONFIG_HID_CMEDIA is not set
|
# CONFIG_HID_CMEDIA is not set
|
||||||
@@ -1925,7 +1944,6 @@ CONFIG_HID_REDRAGON=y
|
|||||||
# CONFIG_HID_PLAYSTATION is not set
|
# CONFIG_HID_PLAYSTATION is not set
|
||||||
# CONFIG_HID_PRIMAX is not set
|
# CONFIG_HID_PRIMAX is not set
|
||||||
# CONFIG_HID_SAITEK is not set
|
# CONFIG_HID_SAITEK is not set
|
||||||
# CONFIG_HID_SAMSUNG is not set
|
|
||||||
# CONFIG_HID_SEMITEK is not set
|
# CONFIG_HID_SEMITEK is not set
|
||||||
# CONFIG_HID_SPEEDLINK is not set
|
# CONFIG_HID_SPEEDLINK is not set
|
||||||
# CONFIG_HID_STEAM is not set
|
# CONFIG_HID_STEAM is not set
|
||||||
@@ -1982,9 +2000,10 @@ CONFIG_DMA_VIRTUAL_CHANNELS=y
|
|||||||
CONFIG_DMA_ACPI=y
|
CONFIG_DMA_ACPI=y
|
||||||
# CONFIG_ALTERA_MSGDMA is not set
|
# CONFIG_ALTERA_MSGDMA is not set
|
||||||
# CONFIG_INTEL_IDMA64 is not set
|
# CONFIG_INTEL_IDMA64 is not set
|
||||||
# CONFIG_INTEL_IDXD is not set
|
# CONFIG_INTEL_IDXD_COMPAT is not set
|
||||||
# CONFIG_INTEL_IOATDMA is not set
|
# CONFIG_INTEL_IOATDMA is not set
|
||||||
# CONFIG_PLX_DMA is not set
|
# CONFIG_PLX_DMA is not set
|
||||||
|
# CONFIG_AMD_PTDMA is not set
|
||||||
# CONFIG_QCOM_HIDMA_MGMT is not set
|
# CONFIG_QCOM_HIDMA_MGMT is not set
|
||||||
# CONFIG_QCOM_HIDMA is not set
|
# CONFIG_QCOM_HIDMA is not set
|
||||||
CONFIG_DW_DMAC_CORE=y
|
CONFIG_DW_DMAC_CORE=y
|
||||||
@@ -2006,8 +2025,6 @@ CONFIG_HSU_DMA=y
|
|||||||
# DMABUF options
|
# DMABUF options
|
||||||
#
|
#
|
||||||
# CONFIG_SYNC_FILE is not set
|
# CONFIG_SYNC_FILE is not set
|
||||||
# CONFIG_DMABUF_MOVE_NOTIFY is not set
|
|
||||||
# CONFIG_DMABUF_DEBUG is not set
|
|
||||||
# CONFIG_DMABUF_HEAPS is not set
|
# CONFIG_DMABUF_HEAPS is not set
|
||||||
# end of DMABUF options
|
# end of DMABUF options
|
||||||
|
|
||||||
@@ -2023,14 +2040,15 @@ CONFIG_UIO_DMEM_GENIRQ=y
|
|||||||
# CONFIG_UIO_PRUSS is not set
|
# CONFIG_UIO_PRUSS is not set
|
||||||
# CONFIG_UIO_MF624 is not set
|
# CONFIG_UIO_MF624 is not set
|
||||||
# CONFIG_UIO_HV_GENERIC is not set
|
# CONFIG_UIO_HV_GENERIC is not set
|
||||||
|
CONFIG_VFIO=y
|
||||||
CONFIG_VFIO_IOMMU_TYPE1=y
|
CONFIG_VFIO_IOMMU_TYPE1=y
|
||||||
CONFIG_VFIO_VIRQFD=y
|
CONFIG_VFIO_VIRQFD=y
|
||||||
CONFIG_VFIO=y
|
|
||||||
# CONFIG_VFIO_NOIOMMU is not set
|
# CONFIG_VFIO_NOIOMMU is not set
|
||||||
CONFIG_VFIO_PCI=y
|
CONFIG_VFIO_PCI_CORE=y
|
||||||
# CONFIG_VFIO_PCI_VGA is not set
|
|
||||||
CONFIG_VFIO_PCI_MMAP=y
|
CONFIG_VFIO_PCI_MMAP=y
|
||||||
CONFIG_VFIO_PCI_INTX=y
|
CONFIG_VFIO_PCI_INTX=y
|
||||||
|
CONFIG_VFIO_PCI=y
|
||||||
|
# CONFIG_VFIO_PCI_VGA is not set
|
||||||
# CONFIG_VFIO_PCI_IGD is not set
|
# CONFIG_VFIO_PCI_IGD is not set
|
||||||
# CONFIG_VFIO_MDEV is not set
|
# CONFIG_VFIO_MDEV is not set
|
||||||
CONFIG_IRQ_BYPASS_MANAGER=y
|
CONFIG_IRQ_BYPASS_MANAGER=y
|
||||||
@@ -2102,6 +2120,8 @@ CONFIG_IOMMU_SUPPORT=y
|
|||||||
# end of Generic IOMMU Pagetable Support
|
# end of Generic IOMMU Pagetable Support
|
||||||
|
|
||||||
# CONFIG_IOMMU_DEBUGFS is not set
|
# CONFIG_IOMMU_DEBUGFS is not set
|
||||||
|
# CONFIG_IOMMU_DEFAULT_DMA_STRICT is not set
|
||||||
|
CONFIG_IOMMU_DEFAULT_DMA_LAZY=y
|
||||||
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
# CONFIG_IOMMU_DEFAULT_PASSTHROUGH is not set
|
||||||
CONFIG_IOMMU_DMA=y
|
CONFIG_IOMMU_DMA=y
|
||||||
# CONFIG_AMD_IOMMU is not set
|
# CONFIG_AMD_IOMMU is not set
|
||||||
@@ -2272,7 +2292,6 @@ CONFIG_FS_POSIX_ACL=y
|
|||||||
CONFIG_EXPORTFS=y
|
CONFIG_EXPORTFS=y
|
||||||
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
# CONFIG_EXPORTFS_BLOCK_OPS is not set
|
||||||
CONFIG_FILE_LOCKING=y
|
CONFIG_FILE_LOCKING=y
|
||||||
CONFIG_MANDATORY_FILE_LOCKING=y
|
|
||||||
CONFIG_FS_ENCRYPTION=y
|
CONFIG_FS_ENCRYPTION=y
|
||||||
CONFIG_FS_ENCRYPTION_ALGS=y
|
CONFIG_FS_ENCRYPTION_ALGS=y
|
||||||
# CONFIG_FS_VERITY is not set
|
# CONFIG_FS_VERITY is not set
|
||||||
@@ -2301,12 +2320,9 @@ CONFIG_NETFS_SUPPORT=y
|
|||||||
# CONFIG_NETFS_STATS is not set
|
# CONFIG_NETFS_STATS is not set
|
||||||
CONFIG_FSCACHE=y
|
CONFIG_FSCACHE=y
|
||||||
# CONFIG_FSCACHE_STATS is not set
|
# CONFIG_FSCACHE_STATS is not set
|
||||||
# CONFIG_FSCACHE_HISTOGRAM is not set
|
|
||||||
# CONFIG_FSCACHE_DEBUG is not set
|
# CONFIG_FSCACHE_DEBUG is not set
|
||||||
# CONFIG_FSCACHE_OBJECT_LIST is not set
|
|
||||||
CONFIG_CACHEFILES=y
|
CONFIG_CACHEFILES=y
|
||||||
# CONFIG_CACHEFILES_DEBUG is not set
|
# CONFIG_CACHEFILES_DEBUG is not set
|
||||||
# CONFIG_CACHEFILES_HISTOGRAM is not set
|
|
||||||
# end of Caches
|
# end of Caches
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -2327,6 +2343,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
|
|||||||
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
# CONFIG_FAT_DEFAULT_UTF8 is not set
|
||||||
# CONFIG_EXFAT_FS is not set
|
# CONFIG_EXFAT_FS is not set
|
||||||
# CONFIG_NTFS_FS is not set
|
# CONFIG_NTFS_FS is not set
|
||||||
|
# CONFIG_NTFS3_FS is not set
|
||||||
# end of DOS/FAT/EXFAT/NT Filesystems
|
# end of DOS/FAT/EXFAT/NT Filesystems
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -2442,6 +2459,8 @@ CONFIG_LSM="yama,loadpin,safesetid,integrity"
|
|||||||
CONFIG_INIT_STACK_NONE=y
|
CONFIG_INIT_STACK_NONE=y
|
||||||
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
|
||||||
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
|
||||||
|
CONFIG_CC_HAS_ZERO_CALL_USED_REGS=y
|
||||||
|
# CONFIG_ZERO_CALL_USED_REGS is not set
|
||||||
# end of Memory initialization
|
# end of Memory initialization
|
||||||
# end of Kernel hardening options
|
# end of Kernel hardening options
|
||||||
# end of Security options
|
# end of Security options
|
||||||
@@ -2587,6 +2606,8 @@ CONFIG_CRYPTO_DES=y
|
|||||||
# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set
|
# CONFIG_CRYPTO_SERPENT_AVX_X86_64 is not set
|
||||||
# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set
|
# CONFIG_CRYPTO_SERPENT_AVX2_X86_64 is not set
|
||||||
# CONFIG_CRYPTO_SM4 is not set
|
# CONFIG_CRYPTO_SM4 is not set
|
||||||
|
# CONFIG_CRYPTO_SM4_AESNI_AVX_X86_64 is not set
|
||||||
|
# CONFIG_CRYPTO_SM4_AESNI_AVX2_X86_64 is not set
|
||||||
# CONFIG_CRYPTO_TWOFISH is not set
|
# CONFIG_CRYPTO_TWOFISH is not set
|
||||||
CONFIG_CRYPTO_TWOFISH_COMMON=y
|
CONFIG_CRYPTO_TWOFISH_COMMON=y
|
||||||
CONFIG_CRYPTO_TWOFISH_X86_64=y
|
CONFIG_CRYPTO_TWOFISH_X86_64=y
|
||||||
@@ -2792,6 +2813,8 @@ CONFIG_HAVE_ARCH_KGDB=y
|
|||||||
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
|
CONFIG_ARCH_HAS_UBSAN_SANITIZE_ALL=y
|
||||||
# CONFIG_UBSAN is not set
|
# CONFIG_UBSAN is not set
|
||||||
CONFIG_HAVE_ARCH_KCSAN=y
|
CONFIG_HAVE_ARCH_KCSAN=y
|
||||||
|
CONFIG_HAVE_KCSAN_COMPILER=y
|
||||||
|
# CONFIG_KCSAN is not set
|
||||||
# end of Generic Kernel Debugging Instruments
|
# end of Generic Kernel Debugging Instruments
|
||||||
|
|
||||||
CONFIG_DEBUG_KERNEL=y
|
CONFIG_DEBUG_KERNEL=y
|
||||||
@@ -2908,7 +2931,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT=59
|
|||||||
# end of RCU Debugging
|
# end of RCU Debugging
|
||||||
|
|
||||||
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
# CONFIG_DEBUG_WQ_FORCE_RR_CPU is not set
|
||||||
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
|
|
||||||
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
# CONFIG_CPU_HOTPLUG_STATE_CONTROL is not set
|
||||||
# CONFIG_LATENCYTOP is not set
|
# CONFIG_LATENCYTOP is not set
|
||||||
CONFIG_USER_STACKTRACE_SUPPORT=y
|
CONFIG_USER_STACKTRACE_SUPPORT=y
|
||||||
@@ -2934,7 +2956,6 @@ CONFIG_STRICT_DEVMEM=y
|
|||||||
#
|
#
|
||||||
# x86 Debugging
|
# x86 Debugging
|
||||||
#
|
#
|
||||||
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
|
|
||||||
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
|
CONFIG_TRACE_IRQFLAGS_NMI_SUPPORT=y
|
||||||
CONFIG_X86_VERBOSE_BOOTUP=y
|
CONFIG_X86_VERBOSE_BOOTUP=y
|
||||||
CONFIG_EARLY_PRINTK=y
|
CONFIG_EARLY_PRINTK=y
|
||||||
@@ -2971,7 +2992,6 @@ CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
|||||||
CONFIG_RUNTIME_TESTING_MENU=y
|
CONFIG_RUNTIME_TESTING_MENU=y
|
||||||
# CONFIG_LKDTM is not set
|
# CONFIG_LKDTM is not set
|
||||||
# CONFIG_TEST_MIN_HEAP is not set
|
# CONFIG_TEST_MIN_HEAP is not set
|
||||||
# CONFIG_TEST_SORT is not set
|
|
||||||
# CONFIG_TEST_DIV64 is not set
|
# CONFIG_TEST_DIV64 is not set
|
||||||
# CONFIG_BACKTRACE_SELF_TEST is not set
|
# CONFIG_BACKTRACE_SELF_TEST is not set
|
||||||
# CONFIG_RBTREE_TEST is not set
|
# CONFIG_RBTREE_TEST is not set
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
Name: cloud-hypervisor
|
Name: cloud-hypervisor
|
||||||
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
Summary: Cloud Hypervisor is an open source Virtual Machine Monitor (VMM) that runs on top of KVM.
|
||||||
Version: 20.0
|
Version: 22.0
|
||||||
Release: 0%{?dist}
|
Release: 0%{?dist}
|
||||||
License: ASL 2.0 or BSD-3-clause
|
License: ASL 2.0 or BSD-3-clause
|
||||||
Group: Applications/System
|
Group: Applications/System
|
||||||
@@ -112,6 +112,12 @@ rm -rf %{buildroot}
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Mar 03 2022 Rob Bradford <robert.bradford@intel.com> 22.0-0
|
||||||
|
- Update to 22.0
|
||||||
|
|
||||||
|
* Thu Jan 20 2022 Rob Bradford <robert.bradford@intel.com> 21.0-0
|
||||||
|
- Update to 21.0
|
||||||
|
|
||||||
* Thu Dec 02 2021 Sebastien Boeuf <sebastien.boeuf@intel.com> 20.0-0
|
* Thu Dec 02 2021 Sebastien Boeuf <sebastien.boeuf@intel.com> 20.0-0
|
||||||
- Update to 20.0
|
- Update to 20.0
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
rm /tmp/ubuntu-cloudinit.img
|
rm -f /tmp/ubuntu-cloudinit.img
|
||||||
mkdosfs -n cidata -C /tmp/ubuntu-cloudinit.img 8192
|
mkdosfs -n cidata -C /tmp/ubuntu-cloudinit.img 8192
|
||||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/user-data ::
|
||||||
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
mcopy -oi /tmp/ubuntu-cloudinit.img -s test_data/cloud-init/ubuntu/meta-data ::
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
CLI_NAME="Cloud Hypervisor"
|
CLI_NAME="Cloud Hypervisor"
|
||||||
|
|
||||||
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
CTR_IMAGE_TAG="cloudhypervisor/dev"
|
||||||
CTR_IMAGE_VERSION="latest"
|
CTR_IMAGE_VERSION="20220303-0"
|
||||||
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||||
|
|
||||||
DOCKER_RUNTIME="docker"
|
DOCKER_RUNTIME="docker"
|
||||||
@@ -48,32 +48,32 @@ CARGO_TARGET_DIR="${CLH_BUILD_DIR}/cargo_target"
|
|||||||
# Send a decorated message to stdout, followed by a new line
|
# Send a decorated message to stdout, followed by a new line
|
||||||
#
|
#
|
||||||
say() {
|
say() {
|
||||||
[ -t 1 ] && [ -n "$TERM" ] \
|
[ -t 1 ] && [ -n "$TERM" ] &&
|
||||||
&& echo "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" \
|
echo "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" ||
|
||||||
|| echo "[$CLI_NAME] $*"
|
echo "[$CLI_NAME] $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send a decorated message to stdout, without a trailing new line
|
# Send a decorated message to stdout, without a trailing new line
|
||||||
#
|
#
|
||||||
say_noln() {
|
say_noln() {
|
||||||
[ -t 1 ] && [ -n "$TERM" ] \
|
[ -t 1 ] && [ -n "$TERM" ] &&
|
||||||
&& echo -n "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" \
|
echo -n "$(tput setaf 2)[$CLI_NAME]$(tput sgr0) $*" ||
|
||||||
|| echo "[$CLI_NAME] $*"
|
echo "[$CLI_NAME] $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send a text message to stderr
|
# Send a text message to stderr
|
||||||
#
|
#
|
||||||
say_err() {
|
say_err() {
|
||||||
[ -t 2 ] && [ -n "$TERM" ] \
|
[ -t 2 ] && [ -n "$TERM" ] &&
|
||||||
&& echo "$(tput setaf 1)[$CLI_NAME] $*$(tput sgr0)" 1>&2 \
|
echo "$(tput setaf 1)[$CLI_NAME] $*$(tput sgr0)" 1>&2 ||
|
||||||
|| echo "[$CLI_NAME] $*" 1>&2
|
echo "[$CLI_NAME] $*" 1>&2
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send a warning-highlighted text to stdout
|
# Send a warning-highlighted text to stdout
|
||||||
say_warn() {
|
say_warn() {
|
||||||
[ -t 1 ] && [ -n "$TERM" ] \
|
[ -t 1 ] && [ -n "$TERM" ] &&
|
||||||
&& echo "$(tput setaf 3)[$CLI_NAME] $*$(tput sgr0)" \
|
echo "$(tput setaf 3)[$CLI_NAME] $*$(tput sgr0)" ||
|
||||||
|| echo "[$CLI_NAME] $*"
|
echo "[$CLI_NAME] $*"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Exit with an error message and (optional) code
|
# Exit with an error message and (optional) code
|
||||||
@@ -86,7 +86,7 @@ die() {
|
|||||||
shift 2
|
shift 2
|
||||||
}
|
}
|
||||||
say_err "$@"
|
say_err "$@"
|
||||||
exit $code
|
exit "$code"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Exit with an error message if the last exit code is not 0
|
# Exit with an error message if the last exit code is not 0
|
||||||
@@ -101,26 +101,34 @@ ok_or_die() {
|
|||||||
#
|
#
|
||||||
ensure_build_dir() {
|
ensure_build_dir() {
|
||||||
for dir in "$CLH_BUILD_DIR" \
|
for dir in "$CLH_BUILD_DIR" \
|
||||||
"$CLH_INTEGRATION_WORKLOADS" \
|
"$CLH_INTEGRATION_WORKLOADS" \
|
||||||
"$CLH_CTR_BUILD_DIR" \
|
"$CLH_CTR_BUILD_DIR" \
|
||||||
"$CARGO_TARGET_DIR" \
|
"$CARGO_TARGET_DIR" \
|
||||||
"$CARGO_REGISTRY_DIR" \
|
"$CARGO_REGISTRY_DIR" \
|
||||||
"$CARGO_GIT_REGISTRY_DIR"; do
|
"$CARGO_GIT_REGISTRY_DIR"; do
|
||||||
mkdir -p "$dir" || die "Error: cannot create dir $dir"
|
mkdir -p "$dir" || die "Error: cannot create dir $dir"
|
||||||
[ -x "$dir" ] && [ -w "$dir" ] || \
|
[ -x "$dir" ] && [ -w "$dir" ] ||
|
||||||
{
|
{
|
||||||
say "Wrong permissions for $dir. Attempting to fix them ..."
|
say "Wrong permissions for $dir. Attempting to fix them ..."
|
||||||
chmod +x+w "$dir"
|
chmod +x+w "$dir"
|
||||||
} || \
|
} ||
|
||||||
die "Error: wrong permissions for $dir. Should be +x+w"
|
die "Error: wrong permissions for $dir. Should be +x+w"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# Make sure we're using the latest dev container, by just pulling it.
|
# Make sure we're using the latest dev container, by just pulling it.
|
||||||
ensure_latest_ctr() {
|
ensure_latest_ctr() {
|
||||||
$DOCKER_RUNTIME pull "$CTR_IMAGE"
|
if [ "$CTR_IMAGE_VERSION" = "local" ]; then
|
||||||
|
build_container
|
||||||
|
else
|
||||||
|
$DOCKER_RUNTIME pull "$CTR_IMAGE"
|
||||||
|
|
||||||
ok_or_die "Error pulling container image. Aborting."
|
if [ $? -ne 0 ]; then
|
||||||
|
build_container
|
||||||
|
fi
|
||||||
|
|
||||||
|
ok_or_die "Error pulling/building container image. Aborting."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fix main directory permissions after a container ran as root.
|
# Fix main directory permissions after a container ran as root.
|
||||||
@@ -132,14 +140,14 @@ fix_dir_perms() {
|
|||||||
# Yes, running Docker to get elevated privileges, just to chown some files
|
# Yes, running Docker to get elevated privileges, just to chown some files
|
||||||
# is a dirty hack.
|
# is a dirty hack.
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
chown -R "$(id -u):$(id -g)" "$CTR_CLH_ROOT_DIR"
|
chown -R "$(id -u):$(id -g)" "$CTR_CLH_ROOT_DIR"
|
||||||
|
|
||||||
return $1
|
return "$1"
|
||||||
}
|
}
|
||||||
# Process exported volumes argument, separate the volumes and make docker compatible
|
# Process exported volumes argument, separate the volumes and make docker compatible
|
||||||
# Sample input: --volumes /a:/a#/b:/b
|
# Sample input: --volumes /a:/a#/b:/b
|
||||||
@@ -151,8 +159,7 @@ process_volumes_args() {
|
|||||||
fi
|
fi
|
||||||
exported_volumes=""
|
exported_volumes=""
|
||||||
arr_vols=(${arg_vols//#/ })
|
arr_vols=(${arg_vols//#/ })
|
||||||
for var in "${arr_vols[@]}"
|
for var in "${arr_vols[@]}"; do
|
||||||
do
|
|
||||||
parts=(${var//:/ })
|
parts=(${var//:/ })
|
||||||
if [[ ! -e "${parts[0]}" ]]; then
|
if [[ ! -e "${parts[0]}" ]]; then
|
||||||
echo "The volume ${parts[0]} does not exist."
|
echo "The volume ${parts[0]} does not exist."
|
||||||
@@ -163,8 +170,8 @@ process_volumes_args() {
|
|||||||
}
|
}
|
||||||
cmd_help() {
|
cmd_help() {
|
||||||
echo ""
|
echo ""
|
||||||
echo "Cloud Hypervisor $(basename $0)"
|
echo "Cloud Hypervisor $(basename "$0")"
|
||||||
echo "Usage: $(basename $0) <command> [<command args>]"
|
echo "Usage: $(basename "$0") <command> [<command args>]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Available commands:"
|
echo "Available commands:"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -176,7 +183,7 @@ cmd_help() {
|
|||||||
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
||||||
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
||||||
echo ""
|
echo ""
|
||||||
echo " tests [--unit|--cargo|--all] [--libc musl|gnu] [-- [<cargo test args>]]"
|
echo " tests [--unit|--cargo|--all] [--libc musl|gnu] [-- [<test scripts args>] [-- [<test binary args>]]] "
|
||||||
echo " Run the Cloud Hypervisor tests."
|
echo " Run the Cloud Hypervisor tests."
|
||||||
echo " --unit Run the unit tests."
|
echo " --unit Run the unit tests."
|
||||||
echo " --cargo Run the cargo tests."
|
echo " --cargo Run the cargo tests."
|
||||||
@@ -186,13 +193,13 @@ cmd_help() {
|
|||||||
echo " --integration-windows Run the Windows guest integration tests."
|
echo " --integration-windows Run the Windows guest integration tests."
|
||||||
echo " --integration-live-migration Run the live-migration integration tests."
|
echo " --integration-live-migration Run the live-migration integration tests."
|
||||||
echo " --libc Select the C library Cloud Hypervisor will be built against. Default is gnu"
|
echo " --libc Select the C library Cloud Hypervisor will be built against. Default is gnu"
|
||||||
|
echo " --metrics Generate performance metrics"
|
||||||
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
echo " --volumes Hash separated volumes to be exported. Example --volumes /mnt:/mnt#/myvol:/myvol"
|
||||||
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
echo " --hypervisor Underlying hypervisor. Options kvm, mshv"
|
||||||
echo " --all Run all tests."
|
echo " --all Run all tests."
|
||||||
echo ""
|
echo ""
|
||||||
echo " build-container [--type]"
|
echo " build-container [--type]"
|
||||||
echo " Build the Cloud Hypervisor container."
|
echo " Build the Cloud Hypervisor container."
|
||||||
echo " --dev Build dev container. This is the default."
|
|
||||||
echo ""
|
echo ""
|
||||||
echo " clean [<cargo args>]]"
|
echo " clean [<cargo args>]]"
|
||||||
echo " Remove the Cloud Hypervisor artifacts."
|
echo " Remove the Cloud Hypervisor artifacts."
|
||||||
@@ -213,37 +220,47 @@ cmd_build() {
|
|||||||
features_build=""
|
features_build=""
|
||||||
exported_device="/dev/kvm"
|
exported_device="/dev/kvm"
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
"-h" | "--help") {
|
||||||
"--debug") { build="debug"; } ;;
|
cmd_help
|
||||||
"--release") { build="release"; } ;;
|
exit 1
|
||||||
"--libc")
|
} ;;
|
||||||
shift
|
"--debug") { build="debug"; } ;;
|
||||||
[[ "$1" =~ ^(musl|gnu)$ ]] || \
|
"--release") { build="release"; } ;;
|
||||||
die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
|
"--libc")
|
||||||
libc="$1"
|
shift
|
||||||
;;
|
[[ "$1" =~ ^(musl|gnu)$ ]] ||
|
||||||
"--volumes")
|
die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
|
||||||
shift
|
libc="$1"
|
||||||
arg_vols="$1"
|
;;
|
||||||
;;
|
"--volumes")
|
||||||
"--hypervisor")
|
shift
|
||||||
shift
|
arg_vols="$1"
|
||||||
hypervisor="$1"
|
;;
|
||||||
;;
|
"--hypervisor")
|
||||||
"--") { shift; break; } ;;
|
shift
|
||||||
*)
|
hypervisor="$1"
|
||||||
die "Unknown build argument: $1. Please use --help for help."
|
;;
|
||||||
;;
|
"--features")
|
||||||
esac
|
shift
|
||||||
shift
|
features_build="--features $1"
|
||||||
|
;;
|
||||||
|
"--") {
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
} ;;
|
||||||
|
*)
|
||||||
|
die "Unknown build argument: $1. Please use --help for help."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
ensure_build_dir
|
ensure_build_dir
|
||||||
ensure_latest_ctr
|
ensure_latest_ctr
|
||||||
|
|
||||||
process_volumes_args
|
process_volumes_args
|
||||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||||
die "Hypervisor value must be kvm or mshv"
|
die "Hypervisor value must be kvm or mshv"
|
||||||
fi
|
fi
|
||||||
if [[ "$hypervisor" = "mshv" ]]; then
|
if [[ "$hypervisor" = "mshv" ]]; then
|
||||||
@@ -254,25 +271,28 @@ cmd_build() {
|
|||||||
cargo_args=("$@")
|
cargo_args=("$@")
|
||||||
[ $build = "release" ] && cargo_args+=("--release")
|
[ $build = "release" ] && cargo_args+=("--release")
|
||||||
cargo_args+=(--target "$target")
|
cargo_args+=(--target "$target")
|
||||||
[ $(uname -m) = "aarch64" ] && cargo_args+=("--no-default-features")
|
[ "$(uname -m)" = "aarch64" ] && cargo_args+=("--no-default-features")
|
||||||
[ $(uname -m) = "aarch64" ] && cargo_args+=(--features $hypervisor)
|
[ "$(uname -m)" = "aarch64" ] && cargo_args+=(--features "$hypervisor")
|
||||||
|
|
||||||
rustflags=""
|
rustflags=""
|
||||||
if [ $(uname -m) = "aarch64" ] && [ $libc = "musl" ] ; then
|
target_cc=""
|
||||||
|
if [ "$(uname -m)" = "aarch64" ] && [ "$libc" = "musl" ]; then
|
||||||
rustflags="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
rustflags="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||||
|
target_cc="musl-gcc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--volume $exported_device \
|
--volume $exported_device \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--env RUSTFLAGS="$rustflags" \
|
--env RUSTFLAGS="$rustflags" \
|
||||||
"$CTR_IMAGE" \
|
--env TARGET_CC="$target_cc" \
|
||||||
cargo build --all $features_build \
|
"$CTR_IMAGE" \
|
||||||
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
cargo build --all $features_build \
|
||||||
"${cargo_args[@]}" && say "Binaries placed under $CLH_CARGO_TARGET/$target/$build"
|
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
||||||
|
"${cargo_args[@]}" && say "Binaries placed under $CLH_CARGO_TARGET/$target/$build"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_clean() {
|
cmd_clean() {
|
||||||
@@ -282,15 +302,15 @@ cmd_clean() {
|
|||||||
ensure_latest_ctr
|
ensure_latest_ctr
|
||||||
|
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--user "$(id -u):$(id -g)" \
|
--user "$(id -u):$(id -g)" \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
cargo clean \
|
cargo clean \
|
||||||
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
--target-dir "$CTR_CLH_CARGO_TARGET" \
|
||||||
"${cargo_args[@]}"
|
"${cargo_args[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_tests() {
|
cmd_tests() {
|
||||||
unit=false
|
unit=false
|
||||||
@@ -300,43 +320,55 @@ cmd_tests() {
|
|||||||
integration_vfio=false
|
integration_vfio=false
|
||||||
integration_windows=false
|
integration_windows=false
|
||||||
integration_live_migration=false
|
integration_live_migration=false
|
||||||
|
metrics=false
|
||||||
libc="gnu"
|
libc="gnu"
|
||||||
arg_vols=""
|
arg_vols=""
|
||||||
hypervisor="kvm"
|
hypervisor="kvm"
|
||||||
exported_device="/dev/kvm"
|
exported_device="/dev/kvm"
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
"-h" | "--help") {
|
||||||
"--unit") { unit=true; } ;;
|
cmd_help
|
||||||
"--cargo") { cargo=true; } ;;
|
exit 1
|
||||||
"--integration") { integration=true; } ;;
|
} ;;
|
||||||
"--integration-sgx") { integration_sgx=true; } ;;
|
"--unit") { unit=true; } ;;
|
||||||
"--integration-vfio") { integration_vfio=true; } ;;
|
"--cargo") { cargo=true; } ;;
|
||||||
"--integration-windows") { integration_windows=true; } ;;
|
"--integration") { integration=true; } ;;
|
||||||
"--integration-live-migration") { integration_live_migration=true; } ;;
|
"--integration-sgx") { integration_sgx=true; } ;;
|
||||||
"--libc")
|
"--integration-vfio") { integration_vfio=true; } ;;
|
||||||
shift
|
"--integration-windows") { integration_windows=true; } ;;
|
||||||
[[ "$1" =~ ^(musl|gnu)$ ]] || \
|
"--integration-live-migration") { integration_live_migration=true; } ;;
|
||||||
die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
|
"--metrics") { metrics=true; } ;;
|
||||||
libc="$1"
|
"--libc")
|
||||||
;;
|
shift
|
||||||
"--volumes")
|
[[ "$1" =~ ^(musl|gnu)$ ]] ||
|
||||||
shift
|
die "Invalid libc: $1. Valid options are \"musl\" and \"gnu\"."
|
||||||
arg_vols="$1"
|
libc="$1"
|
||||||
;;
|
;;
|
||||||
"--hypervisor")
|
"--volumes")
|
||||||
shift
|
shift
|
||||||
hypervisor="$1"
|
arg_vols="$1"
|
||||||
;;
|
;;
|
||||||
"--all") { cargo=true; unit=true; integration=true; } ;;
|
"--hypervisor")
|
||||||
"--") { shift; break; } ;;
|
shift
|
||||||
*)
|
hypervisor="$1"
|
||||||
die "Unknown tests argument: $1. Please use --help for help."
|
;;
|
||||||
;;
|
"--all") {
|
||||||
esac
|
cargo=true
|
||||||
shift
|
unit=true
|
||||||
|
integration=true
|
||||||
|
} ;;
|
||||||
|
"--") {
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
} ;;
|
||||||
|
*)
|
||||||
|
die "Unknown tests argument: $1. Please use --help for help."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||||
die "Hypervisor value must be kvm or mshv"
|
die "Hypervisor value must be kvm or mshv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -344,190 +376,214 @@ cmd_tests() {
|
|||||||
exported_device="/dev/mshv"
|
exported_device="/dev/mshv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -- "$@" '--hypervisor' $hypervisor
|
set -- '--hypervisor' "$hypervisor" "$@"
|
||||||
|
|
||||||
ensure_build_dir
|
ensure_build_dir
|
||||||
ensure_latest_ctr
|
ensure_latest_ctr
|
||||||
|
|
||||||
process_volumes_args
|
process_volumes_args
|
||||||
target="$(uname -m)-unknown-linux-${libc}"
|
target="$(uname -m)-unknown-linux-${libc}"
|
||||||
cflags=""
|
|
||||||
target_cc=""
|
if [[ "$unit" = true ]]; then
|
||||||
if [[ "$target" == "x86_64-unknown-linux-musl" ]]; then
|
say "Running unit tests for $target..."
|
||||||
target_cc="musl-gcc"
|
$DOCKER_RUNTIME run \
|
||||||
cflags="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
|
--rm \
|
||||||
|
--device $exported_device \
|
||||||
|
--device /dev/net/tun \
|
||||||
|
--cap-add net_admin \
|
||||||
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
|
--env BUILD_TARGET="$target" \
|
||||||
|
"$CTR_IMAGE" \
|
||||||
|
./scripts/run_unit_tests.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$unit" = true ]] ; then
|
if [ "$cargo" = true ]; then
|
||||||
say "Running unit tests for $target..."
|
say "Running cargo tests..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--device $exported_device \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--device /dev/net/tun \
|
"$CTR_IMAGE" \
|
||||||
--cap-add net_admin \
|
./scripts/run_cargo_tests.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
|
||||||
--env BUILD_TARGET="$target" \
|
|
||||||
--env CFLAGS="$cflags" \
|
|
||||||
--env TARGET_CC="$target_cc" \
|
|
||||||
"$CTR_IMAGE" \
|
|
||||||
./scripts/run_unit_tests.sh "$@" || fix_dir_perms $? || exit $?
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$cargo" = true ] ; then
|
if [ "$integration" = true ]; then
|
||||||
say "Running cargo tests..."
|
say "Running integration tests for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--privileged \
|
||||||
"$CTR_IMAGE" \
|
--security-opt seccomp=unconfined \
|
||||||
./scripts/run_cargo_tests.sh "$@" || fix_dir_perms $? || exit $?
|
--ipc=host \
|
||||||
|
--net="$CTR_CLH_NET" \
|
||||||
|
--mount type=tmpfs,destination=/tmp \
|
||||||
|
--volume /dev:/dev \
|
||||||
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
|
--env USER="root" \
|
||||||
|
--env CH_LIBC="${libc}" \
|
||||||
|
"$CTR_IMAGE" \
|
||||||
|
./scripts/run_integration_tests_"$(uname -m)".sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$integration" = true ] ; then
|
if [ "$integration_sgx" = true ]; then
|
||||||
say "Running integration tests for $target..."
|
say "Running SGX integration tests for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--mount type=tmpfs,destination=/tmp \
|
--mount type=tmpfs,destination=/tmp \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--env CH_LIBC="${libc}" \
|
--env CH_LIBC="${libc}" \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
./scripts/run_integration_tests_$(uname -m).sh "$@" || fix_dir_perms $? || exit $?
|
./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$integration_sgx" = true ] ; then
|
if [ "$integration_vfio" = true ]; then
|
||||||
say "Running SGX integration tests for $target..."
|
say "Running VFIO integration tests for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--mount type=tmpfs,destination=/tmp \
|
--mount type=tmpfs,destination=/tmp \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--env CH_LIBC="${libc}" \
|
--env CH_LIBC="${libc}" \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
./scripts/run_integration_tests_sgx.sh "$@" || fix_dir_perms $? || exit $?
|
./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$integration_vfio" = true ] ; then
|
if [ "$integration_windows" = true ]; then
|
||||||
say "Running VFIO integration tests for $target..."
|
say "Running Windows integration tests for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--mount type=tmpfs,destination=/tmp \
|
--mount type=tmpfs,destination=/tmp \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--env CH_LIBC="${libc}" \
|
--env CH_LIBC="${libc}" \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
./scripts/run_integration_tests_vfio.sh "$@" || fix_dir_perms $? || exit $?
|
./scripts/run_integration_tests_windows.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$integration_windows" = true ] ; then
|
if [ "$integration_live_migration" = true ]; then
|
||||||
say "Running Windows integration tests for $target..."
|
say "Running 'live migration' integration tests for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--mount type=tmpfs,destination=/tmp \
|
--mount type=tmpfs,destination=/tmp \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--env CH_LIBC="${libc}" \
|
--env CH_LIBC="${libc}" \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
./scripts/run_integration_tests_windows.sh "$@" || fix_dir_perms $? || exit $?
|
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$integration_live_migration" = true ] ; then
|
if [ "$metrics" = true ]; then
|
||||||
say "Running 'live migration' integration tests for $target..."
|
say "Generating performance metrics for $target..."
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--mount type=tmpfs,destination=/tmp \
|
--mount type=tmpfs,destination=/tmp \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--env CH_LIBC="${libc}" \
|
--env CH_LIBC="${libc}" \
|
||||||
"$CTR_IMAGE" \
|
"$CTR_IMAGE" \
|
||||||
./scripts/run_integration_tests_live_migration.sh "$@" || fix_dir_perms $? || exit $?
|
./scripts/run_metrics.sh "$@" || fix_dir_perms $? || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fix_dir_perms $?
|
fix_dir_perms $?
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_build-container() {
|
build_container() {
|
||||||
container_type="dev"
|
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
|
||||||
"--dev") { container_type="dev"; } ;;
|
|
||||||
"--") { shift; break; } ;;
|
|
||||||
*)
|
|
||||||
die "Unknown build-container argument: $1. Please use --help for help."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
ensure_build_dir
|
ensure_build_dir
|
||||||
ensure_latest_ctr
|
|
||||||
|
|
||||||
BUILD_DIR=/tmp/cloud-hypervisor/container/
|
BUILD_DIR=/tmp/cloud-hypervisor/container/
|
||||||
|
|
||||||
mkdir -p $BUILD_DIR
|
mkdir -p $BUILD_DIR
|
||||||
cp $CLH_DOCKERFILE $BUILD_DIR
|
cp "$CLH_DOCKERFILE" $BUILD_DIR
|
||||||
|
|
||||||
[ $(uname -m) = "aarch64" ] && TARGETARCH="arm64"
|
[ "$(uname -m)" = "aarch64" ] && TARGETARCH="arm64"
|
||||||
[ $(uname -m) = "x86_64" ] && TARGETARCH="amd64"
|
[ "$(uname -m)" = "x86_64" ] && TARGETARCH="amd64"
|
||||||
|
|
||||||
$DOCKER_RUNTIME build \
|
$DOCKER_RUNTIME build \
|
||||||
--target $container_type \
|
--target dev \
|
||||||
-t $CTR_IMAGE \
|
-t $CTR_IMAGE \
|
||||||
-f $BUILD_DIR/Dockerfile \
|
-f $BUILD_DIR/Dockerfile \
|
||||||
--build-arg TARGETARCH=$TARGETARCH \
|
--build-arg TARGETARCH=$TARGETARCH \
|
||||||
$BUILD_DIR
|
$BUILD_DIR
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_build-container() {
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
"-h" | "--help") {
|
||||||
|
cmd_help
|
||||||
|
exit 1
|
||||||
|
} ;;
|
||||||
|
"--") {
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
} ;;
|
||||||
|
*)
|
||||||
|
die "Unknown build-container argument: $1. Please use --help for help."
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
build_container
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_shell() {
|
cmd_shell() {
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
"-h"|"--help") { cmd_help; exit 1; } ;;
|
"-h" | "--help") {
|
||||||
"--volumes")
|
cmd_help
|
||||||
shift
|
exit 1
|
||||||
arg_vols="$1"
|
} ;;
|
||||||
;;
|
"--volumes")
|
||||||
"--") { shift; break; } ;;
|
shift
|
||||||
*)
|
arg_vols="$1"
|
||||||
;;
|
;;
|
||||||
esac
|
"--") {
|
||||||
shift
|
shift
|
||||||
|
break
|
||||||
|
} ;;
|
||||||
|
*) ;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
shift
|
||||||
done
|
done
|
||||||
ensure_build_dir
|
ensure_build_dir
|
||||||
ensure_latest_ctr
|
ensure_latest_ctr
|
||||||
@@ -535,20 +591,20 @@ cmd_shell() {
|
|||||||
say_warn "Starting a privileged shell prompt as root ..."
|
say_warn "Starting a privileged shell prompt as root ..."
|
||||||
say_warn "WARNING: Your $CLH_ROOT_DIR folder will be bind-mounted in the container under $CTR_CLH_ROOT_DIR"
|
say_warn "WARNING: Your $CLH_ROOT_DIR folder will be bind-mounted in the container under $CTR_CLH_ROOT_DIR"
|
||||||
$DOCKER_RUNTIME run \
|
$DOCKER_RUNTIME run \
|
||||||
-ti \
|
-ti \
|
||||||
--workdir "$CTR_CLH_ROOT_DIR" \
|
--workdir "$CTR_CLH_ROOT_DIR" \
|
||||||
--rm \
|
--rm \
|
||||||
--privileged \
|
--privileged \
|
||||||
--security-opt seccomp=unconfined \
|
--security-opt seccomp=unconfined \
|
||||||
--ipc=host \
|
--ipc=host \
|
||||||
--net="$CTR_CLH_NET" \
|
--net="$CTR_CLH_NET" \
|
||||||
--tmpfs /tmp:exec \
|
--tmpfs /tmp:exec \
|
||||||
--volume /dev:/dev \
|
--volume /dev:/dev \
|
||||||
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
--volume "$CLH_ROOT_DIR:$CTR_CLH_ROOT_DIR" $exported_volumes \
|
||||||
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
--volume "$CLH_INTEGRATION_WORKLOADS:$CTR_CLH_INTEGRATION_WORKLOADS" \
|
||||||
--env USER="root" \
|
--env USER="root" \
|
||||||
--entrypoint bash \
|
--entrypoint bash \
|
||||||
"$CTR_IMAGE"
|
"$CTR_IMAGE"
|
||||||
|
|
||||||
fix_dir_perms $?
|
fix_dir_perms $?
|
||||||
}
|
}
|
||||||
@@ -557,14 +613,20 @@ cmd_shell() {
|
|||||||
#
|
#
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
-h|--help) { cmd_help; exit 1; } ;;
|
-h | --help) {
|
||||||
-y|--unattended) { OPT_UNATTENDED=true; } ;;
|
cmd_help
|
||||||
-*)
|
exit 1
|
||||||
die "Unknown arg: $1. Please use \`$0 help\` for help."
|
} ;;
|
||||||
;;
|
--local) {
|
||||||
*)
|
CTR_IMAGE_VERSION="local"
|
||||||
break
|
CTR_IMAGE="${CTR_IMAGE_TAG}:${CTR_IMAGE_VERSION}"
|
||||||
;;
|
} ;;
|
||||||
|
-*)
|
||||||
|
die "Unknown arg: $1. Please use \`$0 help\` for help."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
@@ -572,11 +634,10 @@ done
|
|||||||
# $1 is now a command name. Check if it is a valid command and, if so,
|
# $1 is now a command name. Check if it is a valid command and, if so,
|
||||||
# run it.
|
# run it.
|
||||||
#
|
#
|
||||||
declare -f "cmd_$1" > /dev/null
|
declare -f "cmd_$1" >/dev/null
|
||||||
ok_or_die "Unknown command: $1. Please use \`$0 help\` for help."
|
ok_or_die "Unknown command: $1. Please use \`$0 help\` for help."
|
||||||
|
|
||||||
cmd=cmd_$1
|
cmd=cmd_$1
|
||||||
shift
|
shift
|
||||||
|
|
||||||
|
|
||||||
$cmd "$@"
|
$cmd "$@"
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ checkout_repo() {
|
|||||||
build_custom_linux() {
|
build_custom_linux() {
|
||||||
SRCDIR=$PWD
|
SRCDIR=$PWD
|
||||||
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
||||||
LINUX_CUSTOM_BRANCH="ch-5.14"
|
LINUX_CUSTOM_BRANCH="ch-5.15.12"
|
||||||
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
LINUX_CUSTOM_URL="https://github.com/cloud-hypervisor/linux.git"
|
||||||
|
|
||||||
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
checkout_repo "$LINUX_CUSTOM_DIR" "$LINUX_CUSTOM_URL" "$LINUX_CUSTOM_BRANCH"
|
||||||
@@ -102,6 +102,25 @@ build_edk2() {
|
|||||||
popd
|
popd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_spdk_nvme() {
|
||||||
|
SPDK_DIR="$WORKLOADS_DIR/spdk"
|
||||||
|
SPDK_REPO="https://github.com/spdk/spdk.git"
|
||||||
|
checkout_repo "$SPDK_DIR" "$SPDK_REPO" master "f9c496b8e21a8f499df268818bf8b5d8e2b19f04"
|
||||||
|
|
||||||
|
pushd $SPDK_DIR
|
||||||
|
git submodule update --init
|
||||||
|
apt-get update
|
||||||
|
./scripts/pkgdep.sh
|
||||||
|
./configure --with-vfio-user
|
||||||
|
chmod +x /usr/local/lib/python3.8/dist-packages/ninja/data/bin/ninja
|
||||||
|
make -j `nproc`
|
||||||
|
mkdir /usr/local/bin/spdk-nvme
|
||||||
|
cp ./build/bin/nvmf_tgt /usr/local/bin/spdk-nvme
|
||||||
|
cp ./scripts/rpc.py /usr/local/bin/spdk-nvme
|
||||||
|
cp -r ./scripts/rpc /usr/local/bin/spdk-nvme
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
update_workloads() {
|
update_workloads() {
|
||||||
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
|
cp scripts/sha1sums-aarch64 $WORKLOADS_DIR
|
||||||
|
|
||||||
@@ -198,17 +217,17 @@ update_workloads() {
|
|||||||
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
guestunmount "$FOCAL_OS_RAW_IMAGE_UPDATE_KERNEL_ROOT_DIR"
|
||||||
|
|
||||||
# Build virtiofsd
|
# Build virtiofsd
|
||||||
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
|
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||||
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
|
VIRTIOFSD_DIR="virtiofsd_build"
|
||||||
if [ ! -f "$VIRTIOFSD_RS" ]; then
|
if [ ! -f "$VIRTIOFSD" ]; then
|
||||||
pushd $WORKLOADS_DIR
|
pushd $WORKLOADS_DIR
|
||||||
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
git clone "https://gitlab.com/virtio-fs/virtiofsd.git" $VIRTIOFSD_DIR
|
||||||
pushd $VIRTIOFSD_RS_DIR
|
pushd $VIRTIOFSD_DIR
|
||||||
git checkout 21d20035a582fb0389697b1bd7f8331623a77939
|
git checkout v1.1.0
|
||||||
time cargo build --release
|
time cargo build --release
|
||||||
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
|
cp target/release/virtiofsd $VIRTIOFSD || exit 1
|
||||||
popd
|
popd
|
||||||
rm -rf $VIRTIOFSD_RS_DIR
|
rm -rf $VIRTIOFSD_DIR
|
||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -233,6 +252,9 @@ update_workloads() {
|
|||||||
echo "bar" > "$SHARED_DIR/file3" || exit 1
|
echo "bar" > "$SHARED_DIR/file3" || exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# checkout and build SPDK NVMe
|
||||||
|
build_spdk_nvme
|
||||||
|
|
||||||
# Check and build EDK2 binary
|
# Check and build EDK2 binary
|
||||||
build_edk2
|
build_edk2
|
||||||
}
|
}
|
||||||
@@ -245,8 +267,8 @@ if [[ "$hypervisor" = "mshv" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
features_build=""
|
# For now these values are deafult for kvm
|
||||||
features_test="--features integration_tests"
|
features=""
|
||||||
|
|
||||||
# lock the workloads folder to avoid parallel updating by different containers
|
# lock the workloads folder to avoid parallel updating by different containers
|
||||||
(
|
(
|
||||||
@@ -263,17 +285,15 @@ if [ $RES -ne 0 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
BUILD_TARGET="aarch64-unknown-linux-${CH_LIBC}"
|
||||||
CFLAGS=""
|
|
||||||
TARGET_CC=""
|
|
||||||
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
if [[ "${BUILD_TARGET}" == "aarch64-unknown-linux-musl" ]]; then
|
||||||
TARGET_CC="musl-gcc"
|
export TARGET_CC="musl-gcc"
|
||||||
CFLAGS="-I /usr/include/aarch64-linux-musl/ -idirafter /usr/include/"
|
export RUSTFLAGS="-C link-arg=-lgcc -C link_arg=-specs -C link_arg=/usr/lib/aarch64-linux-musl/musl-gcc.specs"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
|
|
||||||
# Test without ACPI
|
# Test without ACPI
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||||
strip target/$BUILD_TARGET/release/ch-remote
|
strip target/$BUILD_TARGET/release/ch-remote
|
||||||
@@ -284,17 +304,18 @@ sudo bash -c "echo 1000000 > /sys/kernel/mm/ksm/pages_to_scan"
|
|||||||
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
sudo bash -c "echo 10 > /sys/kernel/mm/ksm/sleep_millisecs"
|
||||||
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
sudo bash -c "echo 1 > /sys/kernel/mm/ksm/run"
|
||||||
|
|
||||||
# Setup huge-pages for ovs-dpdk
|
# Both test_vfio and ovs-dpdk rely on hugepages
|
||||||
echo 2048 | sudo tee /proc/sys/vm/nr_hugepages
|
echo 6144 | 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`
|
# Run all direct kernel boot (Device Tree) test cases in mod `parallel`
|
||||||
time cargo test $features_test "tests::parallel::$test_filter"
|
time cargo test $features "parallel::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
# Run some tests in sequence since the result could be affected by other tests
|
# Run some tests in sequence since the result could be affected by other tests
|
||||||
# running in parallel.
|
# running in parallel.
|
||||||
if [ $RES -eq 0 ]; then
|
if [ $RES -eq 0 ]; then
|
||||||
time cargo test $features_test "tests::sequential::$test_filter" -- --test-threads=1
|
time cargo test $features "sequential::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
else
|
else
|
||||||
exit $RES
|
exit $RES
|
||||||
@@ -302,7 +323,7 @@ fi
|
|||||||
|
|
||||||
# Run all ACPI test cases
|
# Run all ACPI test cases
|
||||||
if [ $RES -eq 0 ]; then
|
if [ $RES -eq 0 ]; then
|
||||||
time cargo test $features_test "tests::aarch64_acpi::$test_filter"
|
time cargo test $features "aarch64_acpi::$test_filter" --target $BUILD_TARGET -- ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
else
|
else
|
||||||
exit $RES
|
exit $RES
|
||||||
@@ -310,7 +331,7 @@ fi
|
|||||||
|
|
||||||
# Run all test cases related to live migration
|
# Run all test cases related to live migration
|
||||||
if [ $RES -eq 0 ]; then
|
if [ $RES -eq 0 ]; then
|
||||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
time cargo test $features "live_migration::$test_filter" --target $BUILD_TARGET -- --test-threads=1 ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
else
|
else
|
||||||
exit $RES
|
exit $RES
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ mkdir -p "$WORKLOADS_DIR"
|
|||||||
|
|
||||||
process_common_args "$@"
|
process_common_args "$@"
|
||||||
|
|
||||||
# For now these values are deafult for kvm
|
# For now these values are default for kvm
|
||||||
features_build=""
|
features=""
|
||||||
features_test="--features integration_tests"
|
|
||||||
|
|
||||||
if [ "$hypervisor" = "mshv" ] ; then
|
if [ "$hypervisor" = "mshv" ] ; then
|
||||||
features_build="--no-default-features --features mshv,common"
|
features="--no-default-features --features mshv,common"
|
||||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||||
@@ -55,7 +53,7 @@ LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
|||||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||||
SRCDIR=$PWD
|
SRCDIR=$PWD
|
||||||
pushd $WORKLOADS_DIR
|
pushd $WORKLOADS_DIR
|
||||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
|
||||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
@@ -79,7 +77,7 @@ if [[ "${BUILD_TARGET}" == "x86_64-unknown-linux-musl" ]]; then
|
|||||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||||
strip target/$BUILD_TARGET/release/ch-remote
|
strip target/$BUILD_TARGET/release/ch-remote
|
||||||
@@ -89,7 +87,7 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
|||||||
sudo chmod a+rwX /dev/hugepages
|
sudo chmod a+rwX /dev/hugepages
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
time cargo test $features_test "tests::live_migration::$test_filter" -- --test-threads=1
|
time cargo test $features "live_migration::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
exit $RES
|
exit $RES
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ if [[ "$hypervisor" = "mshv" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For now these values are deafult for kvm
|
# For now these values are default for kvm
|
||||||
features_build=""
|
features=""
|
||||||
features_test="--features integration_tests"
|
|
||||||
|
|
||||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||||
CFLAGS=""
|
CFLAGS=""
|
||||||
@@ -23,12 +22,12 @@ TARGET_CC="musl-gcc"
|
|||||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
|
|
||||||
time cargo test $features_test "tests::sgx::$test_filter"
|
time cargo test $features "sgx::$test_filter" -- ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
exit $RES
|
exit $RES
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ source $HOME/.cargo/env
|
|||||||
source $(dirname "$0")/test-util.sh
|
source $(dirname "$0")/test-util.sh
|
||||||
|
|
||||||
process_common_args "$@"
|
process_common_args "$@"
|
||||||
# For now these values are deafult for kvm
|
# For now these values are default for kvm
|
||||||
features_build=""
|
features=""
|
||||||
features_test="--features integration_tests"
|
|
||||||
|
|
||||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||||
CFLAGS=""
|
CFLAGS=""
|
||||||
@@ -17,12 +16,12 @@ TARGET_CC="musl-gcc"
|
|||||||
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
|
|
||||||
time cargo test $features_test "tests::vfio::$test_filter" -- --test-threads=1
|
time cargo test $features "vfio::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
exit $RES
|
exit $RES
|
||||||
|
|||||||
@@ -5,16 +5,23 @@ source $HOME/.cargo/env
|
|||||||
source $(dirname "$0")/test-util.sh
|
source $(dirname "$0")/test-util.sh
|
||||||
|
|
||||||
process_common_args "$@"
|
process_common_args "$@"
|
||||||
# For now these values are deafult for kvm
|
# For now these values are default for kvm
|
||||||
features_build=""
|
features=""
|
||||||
features_test="--features integration_tests"
|
|
||||||
|
|
||||||
if [ "$hypervisor" = "mshv" ] ; then
|
if [ "$hypervisor" = "mshv" ] ; then
|
||||||
features_build="--no-default-features --features mshv,common"
|
features="--no-default-features --features mshv,common"
|
||||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
|
||||||
fi
|
fi
|
||||||
WIN_IMAGE_FILE="/root/workloads/windows-server-2019.raw"
|
WIN_IMAGE_FILE="/root/workloads/windows-server-2019.raw"
|
||||||
OVMF_FW_FILE="/root/workloads/OVMF-4b47d0c6c8.fd"
|
|
||||||
|
WORKLOADS_DIR="/root/workloads"
|
||||||
|
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||||
|
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||||
|
if [ ! -f "$OVMF_FW" ]; then
|
||||||
|
pushd $WORKLOADS_DIR
|
||||||
|
time wget --quiet $OVMF_FW_URL || exit 1
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
||||||
CFLAGS=""
|
CFLAGS=""
|
||||||
TARGET_CC=""
|
TARGET_CC=""
|
||||||
@@ -24,7 +31,7 @@ CFLAGS="-I /usr/include/x86_64-linux-musl/ -idirafter /usr/include/"
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if the images are present
|
# Check if the images are present
|
||||||
if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW_FILE} ]]; then
|
if [[ ! -f ${WIN_IMAGE_FILE} || ! -f ${OVMF_FW} ]]; then
|
||||||
echo "Windows image/firmware not present in the host"
|
echo "Windows image/firmware not present in the host"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -37,14 +44,14 @@ dmsetup mknodes
|
|||||||
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
|
dmsetup create windows-snapshot-base --table "0 $img_blk_size snapshot-origin /dev/mapper/windows-base"
|
||||||
dmsetup mknodes
|
dmsetup mknodes
|
||||||
|
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
|
|
||||||
# Only run with 1 thread to avoid tests interfering with one another because
|
# Only run with 1 thread to avoid tests interfering with one another because
|
||||||
# Windows has a static IP configured
|
# Windows has a static IP configured
|
||||||
time cargo test $features_test "tests::windows::$test_filter"
|
time cargo test $features "windows::$test_filter" -- ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
dmsetup remove_all -f
|
dmsetup remove_all -f
|
||||||
|
|||||||
@@ -11,13 +11,11 @@ mkdir -p "$WORKLOADS_DIR"
|
|||||||
|
|
||||||
process_common_args "$@"
|
process_common_args "$@"
|
||||||
|
|
||||||
# For now these values are deafult for kvm
|
# For now these values are default for kvm
|
||||||
features_build=""
|
features=""
|
||||||
features_test="--features integration_tests"
|
|
||||||
|
|
||||||
if [ "$hypervisor" = "mshv" ] ; then
|
if [ "$hypervisor" = "mshv" ] ; then
|
||||||
features_build="--no-default-features --features mshv,common"
|
features="--no-default-features --features mshv,common"
|
||||||
features_test="--no-default-features --features mshv,common,integration_tests"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||||
@@ -30,6 +28,14 @@ if [ ! -f "$FW" ]; then
|
|||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
OVMF_FW_URL=$(curl --silent https://api.github.com/repos/cloud-hypervisor/edk2/releases/latest | grep "browser_download_url" | grep -o 'https://.*[^ "]')
|
||||||
|
OVMF_FW="$WORKLOADS_DIR/CLOUDHV.fd"
|
||||||
|
if [ ! -f "$OVMF_FW" ]; then
|
||||||
|
pushd $WORKLOADS_DIR
|
||||||
|
time wget --quiet $OVMF_FW_URL || exit 1
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
BIONIC_OS_IMAGE_NAME="bionic-server-cloudimg-amd64.qcow2"
|
BIONIC_OS_IMAGE_NAME="bionic-server-cloudimg-amd64.qcow2"
|
||||||
BIONIC_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_NAME"
|
BIONIC_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$BIONIC_OS_IMAGE_NAME"
|
||||||
BIONIC_OS_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_NAME"
|
BIONIC_OS_IMAGE="$WORKLOADS_DIR/$BIONIC_OS_IMAGE_NAME"
|
||||||
@@ -107,7 +113,7 @@ LINUX_CUSTOM_DIR="$WORKLOADS_DIR/linux-custom"
|
|||||||
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||||
SRCDIR=$PWD
|
SRCDIR=$PWD
|
||||||
pushd $WORKLOADS_DIR
|
pushd $WORKLOADS_DIR
|
||||||
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.14" $LINUX_CUSTOM_DIR
|
time git clone --depth 1 "https://github.com/cloud-hypervisor/linux.git" -b "ch-5.15.12" $LINUX_CUSTOM_DIR
|
||||||
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
@@ -123,17 +129,17 @@ if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
|||||||
rm -rf $LINUX_CUSTOM_DIR
|
rm -rf $LINUX_CUSTOM_DIR
|
||||||
fi
|
fi
|
||||||
|
|
||||||
VIRTIOFSD_RS="$WORKLOADS_DIR/virtiofsd-rs"
|
VIRTIOFSD="$WORKLOADS_DIR/virtiofsd"
|
||||||
VIRTIOFSD_RS_DIR="virtiofsd_rs_build"
|
VIRTIOFSD_DIR="virtiofsd_build"
|
||||||
if [ ! -f "$VIRTIOFSD_RS" ]; then
|
if [ ! -f "$VIRTIOFSD" ]; then
|
||||||
pushd $WORKLOADS_DIR
|
pushd $WORKLOADS_DIR
|
||||||
git clone "https://gitlab.com/virtio-fs/virtiofsd-rs.git" $VIRTIOFSD_RS_DIR
|
git clone "https://gitlab.com/virtio-fs/virtiofsd.git" $VIRTIOFSD_DIR
|
||||||
pushd $VIRTIOFSD_RS_DIR
|
pushd $VIRTIOFSD_DIR
|
||||||
git checkout 21d20035a582fb0389697b1bd7f8331623a77939
|
git checkout v1.1.0
|
||||||
time cargo build --release
|
time cargo build --release
|
||||||
cp target/release/virtiofsd-rs $VIRTIOFSD_RS || exit 1
|
cp target/release/virtiofsd $VIRTIOFSD || exit 1
|
||||||
popd
|
popd
|
||||||
rm -rf $VIRTIOFSD_RS_DIR
|
rm -rf $VIRTIOFSD_DIR
|
||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -168,14 +174,8 @@ cp $FW $VFIO_DIR
|
|||||||
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
cp $VMLINUX_IMAGE $VFIO_DIR || exit 1
|
||||||
|
|
||||||
BUILD_TARGET="$(uname -m)-unknown-linux-${CH_LIBC}"
|
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/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
cargo build --all --release $features_build --target $BUILD_TARGET
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
strip target/$BUILD_TARGET/release/vhost_user_net
|
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||||
strip target/$BUILD_TARGET/release/ch-remote
|
strip target/$BUILD_TARGET/release/ch-remote
|
||||||
@@ -195,14 +195,14 @@ echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
|||||||
sudo chmod a+rwX /dev/hugepages
|
sudo chmod a+rwX /dev/hugepages
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
time cargo test $features_test "tests::parallel::$test_filter"
|
time cargo test $features "parallel::$test_filter" -- ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
|
|
||||||
# Run some tests in sequence since the result could be affected by other tests
|
# Run some tests in sequence since the result could be affected by other tests
|
||||||
# running in parallel.
|
# running in parallel.
|
||||||
if [ $RES -eq 0 ]; then
|
if [ $RES -eq 0 ]; then
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
time cargo test $features_test "tests::sequential::$test_filter" -- --test-threads=1
|
time cargo test $features "sequential::$test_filter" -- --test-threads=1 ${test_binary_args[*]}
|
||||||
RES=$?
|
RES=$?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
94
scripts/run_metrics.sh
Executable file
94
scripts/run_metrics.sh
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -x
|
||||||
|
|
||||||
|
source $HOME/.cargo/env
|
||||||
|
source $(dirname "$0")/test-util.sh
|
||||||
|
|
||||||
|
export BUILD_TARGET=${BUILD_TARGET-x86_64-unknown-linux-gnu}
|
||||||
|
|
||||||
|
WORKLOADS_DIR="$HOME/workloads"
|
||||||
|
mkdir -p "$WORKLOADS_DIR"
|
||||||
|
|
||||||
|
process_common_args "$@"
|
||||||
|
|
||||||
|
# For now these values are default for kvm
|
||||||
|
features=""
|
||||||
|
|
||||||
|
if [ "$hypervisor" = "mshv" ] ; then
|
||||||
|
features="--no-default-features --features mshv,common"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cp scripts/sha1sums-x86_64 $WORKLOADS_DIR
|
||||||
|
|
||||||
|
FOCAL_OS_IMAGE_NAME="focal-server-cloudimg-amd64-custom-20210609-0.qcow2"
|
||||||
|
FOCAL_OS_IMAGE_URL="https://cloud-hypervisor.azureedge.net/$FOCAL_OS_IMAGE_NAME"
|
||||||
|
FOCAL_OS_IMAGE="$WORKLOADS_DIR/$FOCAL_OS_IMAGE_NAME"
|
||||||
|
if [ ! -f "$FOCAL_OS_IMAGE" ]; then
|
||||||
|
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
|
||||||
|
grep focal sha1sums-x86_64 | sha1sum --check
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "sha1sum validation of images failed, remove invalid images to fix the issue."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
popd
|
||||||
|
|
||||||
|
# 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-5.15.12" $LINUX_CUSTOM_DIR
|
||||||
|
cp $SRCDIR/resources/linux-config-x86_64 $LINUX_CUSTOM_DIR/.config
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$VMLINUX_IMAGE" ]; then
|
||||||
|
pushd $LINUX_CUSTOM_DIR
|
||||||
|
time make bzImage -j `nproc`
|
||||||
|
cp vmlinux $VMLINUX_IMAGE || exit 1
|
||||||
|
popd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -d "$LINUX_CUSTOM_DIR" ]; then
|
||||||
|
rm -rf $LINUX_CUSTOM_DIR
|
||||||
|
fi
|
||||||
|
|
||||||
|
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/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cargo build --all --release $features --target $BUILD_TARGET
|
||||||
|
strip target/$BUILD_TARGET/release/cloud-hypervisor
|
||||||
|
strip target/$BUILD_TARGET/release/vhost_user_net
|
||||||
|
strip target/$BUILD_TARGET/release/ch-remote
|
||||||
|
strip target/$BUILD_TARGET/release/performance-metrics
|
||||||
|
|
||||||
|
# setup hugepages
|
||||||
|
echo 6144 | sudo tee /proc/sys/vm/nr_hugepages
|
||||||
|
sudo chmod a+rwX /dev/hugepages
|
||||||
|
|
||||||
|
export RUST_BACKTRACE=1
|
||||||
|
time target/$BUILD_TARGET/release/performance-metrics ${test_binary_args[*]}
|
||||||
|
RES=$?
|
||||||
|
|
||||||
|
exit $RES
|
||||||
@@ -12,5 +12,11 @@ if [[ $(uname -m) = "aarch64" || $hypervisor = "mshv" ]]; then
|
|||||||
cargo_args+=("--no-default-features")
|
cargo_args+=("--no-default-features")
|
||||||
cargo_args+=("--features $hypervisor")
|
cargo_args+=("--features $hypervisor")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
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"
|
||||||
|
fi
|
||||||
|
|
||||||
export RUST_BACKTRACE=1
|
export RUST_BACKTRACE=1
|
||||||
cargo test --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1;
|
cargo test --lib --bins --target $BUILD_TARGET --workspace ${cargo_args[@]} || exit 1;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
hypervisor="kvm"
|
hypervisor="kvm"
|
||||||
test_filter=""
|
test_filter=""
|
||||||
|
test_binary_args=()
|
||||||
|
|
||||||
cmd_help() {
|
cmd_help() {
|
||||||
echo ""
|
echo ""
|
||||||
@@ -28,12 +29,20 @@ process_common_args() {
|
|||||||
shift
|
shift
|
||||||
test_filter="$1"
|
test_filter="$1"
|
||||||
;;
|
;;
|
||||||
|
"--") {
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
} ;;
|
||||||
*)
|
*)
|
||||||
;;
|
echo "Unknown test scripts argument: $1. Please use '-- --help' for help."
|
||||||
|
exit
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
if [[ ! ("$hypervisor" = "kvm" || "$hypervisor" = "mshv") ]]; then
|
||||||
die "Hypervisor value must be kvm or mshv"
|
die "Hypervisor value must be kvm or mshv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
test_binary_args="$@"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ extern crate clap;
|
|||||||
use api_client::simple_api_command;
|
use api_client::simple_api_command;
|
||||||
use api_client::simple_api_command_with_fds;
|
use api_client::simple_api_command_with_fds;
|
||||||
use api_client::Error as ApiClientError;
|
use api_client::Error as ApiClientError;
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
|
use clap::{Arg, ArgMatches, Command};
|
||||||
use option_parser::{ByteSized, ByteSizedParseError};
|
use option_parser::{ByteSized, ByteSizedParseError};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
@@ -263,9 +263,14 @@ fn receive_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(
|
|||||||
.map_err(Error::ApiClient)
|
.map_err(Error::ApiClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_migration_api_command(socket: &mut UnixStream, url: &str) -> Result<(), Error> {
|
fn send_migration_api_command(
|
||||||
|
socket: &mut UnixStream,
|
||||||
|
url: &str,
|
||||||
|
local: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
let send_migration_data = vmm::api::VmSendMigrationData {
|
let send_migration_data = vmm::api::VmSendMigrationData {
|
||||||
destination_url: url.to_owned(),
|
destination_url: url.to_owned(),
|
||||||
|
local,
|
||||||
};
|
};
|
||||||
simple_api_command(
|
simple_api_command(
|
||||||
socket,
|
socket,
|
||||||
@@ -402,6 +407,10 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.value_of("send_migration_config")
|
.value_of("send_migration_config")
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
matches
|
||||||
|
.subcommand_matches("send-migration")
|
||||||
|
.unwrap()
|
||||||
|
.is_present("send_migration_local"),
|
||||||
),
|
),
|
||||||
Some("receive-migration") => receive_migration_api_command(
|
Some("receive-migration") => receive_migration_api_command(
|
||||||
&mut socket,
|
&mut socket,
|
||||||
@@ -417,12 +426,12 @@ fn do_command(matches: &ArgMatches) -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = App::new("ch-remote")
|
let app = Command::new("ch-remote")
|
||||||
.author(crate_authors!())
|
.author(crate_authors!())
|
||||||
.setting(AppSettings::SubcommandRequired)
|
.subcommand_required(true)
|
||||||
.about("Remotely control a cloud-hypervisor VMM.")
|
.about("Remotely control a cloud-hypervisor VMM.")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("api-socket")
|
Arg::new("api-socket")
|
||||||
.long("api-socket")
|
.long("api-socket")
|
||||||
.help("HTTP API socket path (UNIX domain socket).")
|
.help("HTTP API socket path (UNIX domain socket).")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -430,97 +439,89 @@ fn main() {
|
|||||||
.required(true),
|
.required(true),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-device")
|
Command::new("add-device").about("Add VFIO device").arg(
|
||||||
.about("Add VFIO device")
|
Arg::new("device_config")
|
||||||
.arg(
|
.index(1)
|
||||||
Arg::with_name("device_config")
|
.help(vmm::config::DeviceConfig::SYNTAX),
|
||||||
.index(1)
|
),
|
||||||
.help(vmm::config::DeviceConfig::SYNTAX),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-disk")
|
Command::new("add-disk").about("Add block device").arg(
|
||||||
.about("Add block device")
|
Arg::new("disk_config")
|
||||||
.arg(
|
.index(1)
|
||||||
Arg::with_name("disk_config")
|
.help(vmm::config::DiskConfig::SYNTAX),
|
||||||
.index(1)
|
),
|
||||||
.help(vmm::config::DiskConfig::SYNTAX),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-fs")
|
Command::new("add-fs")
|
||||||
.about("Add virtio-fs backed fs device")
|
.about("Add virtio-fs backed fs device")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("fs_config")
|
Arg::new("fs_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::config::FsConfig::SYNTAX),
|
.help(vmm::config::FsConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-pmem")
|
Command::new("add-pmem")
|
||||||
.about("Add persistent memory device")
|
.about("Add persistent memory device")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("pmem_config")
|
Arg::new("pmem_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::config::PmemConfig::SYNTAX),
|
.help(vmm::config::PmemConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-net")
|
Command::new("add-net").about("Add network device").arg(
|
||||||
.about("Add network device")
|
Arg::new("net_config")
|
||||||
.arg(
|
.index(1)
|
||||||
Arg::with_name("net_config")
|
.help(vmm::config::NetConfig::SYNTAX),
|
||||||
.index(1)
|
),
|
||||||
.help(vmm::config::NetConfig::SYNTAX),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-user-device")
|
Command::new("add-user-device")
|
||||||
.about("Add userspace device")
|
.about("Add userspace device")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("device_config")
|
Arg::new("device_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::config::UserDeviceConfig::SYNTAX),
|
.help(vmm::config::UserDeviceConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("add-vsock")
|
Command::new("add-vsock").about("Add vsock device").arg(
|
||||||
.about("Add vsock device")
|
Arg::new("vsock_config")
|
||||||
.arg(
|
.index(1)
|
||||||
Arg::with_name("vsock_config")
|
.help(vmm::config::VsockConfig::SYNTAX),
|
||||||
.index(1)
|
),
|
||||||
.help(vmm::config::VsockConfig::SYNTAX),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("remove-device")
|
Command::new("remove-device")
|
||||||
.about("Remove VFIO device")
|
.about("Remove VFIO device")
|
||||||
.arg(Arg::with_name("id").index(1).help("<device_id>")),
|
.arg(Arg::new("id").index(1).help("<device_id>")),
|
||||||
)
|
)
|
||||||
.subcommand(SubCommand::with_name("info").about("Info on the VM"))
|
.subcommand(Command::new("info").about("Info on the VM"))
|
||||||
.subcommand(SubCommand::with_name("counters").about("Counters from the VM"))
|
.subcommand(Command::new("counters").about("Counters from the VM"))
|
||||||
.subcommand(SubCommand::with_name("pause").about("Pause the VM"))
|
.subcommand(Command::new("pause").about("Pause the VM"))
|
||||||
.subcommand(SubCommand::with_name("reboot").about("Reboot the VM"))
|
.subcommand(Command::new("reboot").about("Reboot the VM"))
|
||||||
.subcommand(SubCommand::with_name("power-button").about("Trigger a power button in the VM"))
|
.subcommand(Command::new("power-button").about("Trigger a power button in the VM"))
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("resize")
|
Command::new("resize")
|
||||||
.about("Resize the VM")
|
.about("Resize the VM")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("cpus")
|
Arg::new("cpus")
|
||||||
.long("cpus")
|
.long("cpus")
|
||||||
.help("New vCPUs count")
|
.help("New vCPUs count")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("memory")
|
Arg::new("memory")
|
||||||
.long("memory")
|
.long("memory")
|
||||||
.help("New memory size in bytes (supports K/M/G suffix)")
|
.help("New memory size in bytes (supports K/M/G suffix)")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("balloon")
|
Arg::new("balloon")
|
||||||
.long("balloon")
|
.long("balloon")
|
||||||
.help("New balloon size in bytes (supports K/M/G suffix)")
|
.help("New balloon size in bytes (supports K/M/G suffix)")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -528,57 +529,62 @@ fn main() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("resize-zone")
|
Command::new("resize-zone")
|
||||||
.about("Resize a memory zone")
|
.about("Resize a memory zone")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("id")
|
Arg::new("id")
|
||||||
.long("id")
|
.long("id")
|
||||||
.help("Memory zone identifier")
|
.help("Memory zone identifier")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("size")
|
Arg::new("size")
|
||||||
.long("size")
|
.long("size")
|
||||||
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
.help("New memory zone size in bytes (supports K/M/G suffix)")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.number_of_values(1),
|
.number_of_values(1),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(SubCommand::with_name("resume").about("Resume the VM"))
|
.subcommand(Command::new("resume").about("Resume the VM"))
|
||||||
.subcommand(SubCommand::with_name("shutdown").about("Shutdown the VM"))
|
.subcommand(Command::new("shutdown").about("Shutdown the VM"))
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("snapshot")
|
Command::new("snapshot")
|
||||||
.about("Create a snapshot from VM")
|
.about("Create a snapshot from VM")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("snapshot_config")
|
Arg::new("snapshot_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help("<destination_url>"),
|
.help("<destination_url>"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("restore")
|
Command::new("restore")
|
||||||
.about("Restore VM from a snapshot")
|
.about("Restore VM from a snapshot")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("restore_config")
|
Arg::new("restore_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help(vmm::config::RestoreConfig::SYNTAX),
|
.help(vmm::config::RestoreConfig::SYNTAX),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("send-migration")
|
Command::new("send-migration")
|
||||||
.about("Initiate a VM migration")
|
.about("Initiate a VM migration")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("send_migration_config")
|
Arg::new("send_migration_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help("<destination_url>"),
|
.help("<destination_url>"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("send_migration_local")
|
||||||
|
.long("local")
|
||||||
|
.takes_value(false),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
SubCommand::with_name("receive-migration")
|
Command::new("receive-migration")
|
||||||
.about("Receive a VM migration")
|
.about("Receive a VM migration")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("receive_migration_config")
|
Arg::new("receive_migration_config")
|
||||||
.index(1)
|
.index(1)
|
||||||
.help("<receiver_url>"),
|
.help("<receiver_url>"),
|
||||||
),
|
),
|
||||||
|
|||||||
311
src/main.rs
311
src/main.rs
@@ -8,7 +8,7 @@ extern crate clap;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate event_monitor;
|
extern crate event_monitor;
|
||||||
|
|
||||||
use clap::{App, Arg, ArgGroup, ArgMatches};
|
use clap::{Arg, ArgGroup, ArgMatches, Command};
|
||||||
use libc::EFD_NONBLOCK;
|
use libc::EFD_NONBLOCK;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use option_parser::OptionParser;
|
use option_parser::OptionParser;
|
||||||
@@ -32,6 +32,9 @@ use vmm_sys_util::signal::block_signal;
|
|||||||
enum Error {
|
enum Error {
|
||||||
#[error("Failed to create API EventFd: {0}")]
|
#[error("Failed to create API EventFd: {0}")]
|
||||||
CreateApiEventFd(#[source] std::io::Error),
|
CreateApiEventFd(#[source] std::io::Error),
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
#[error("Failed to create Debug EventFd: {0}")]
|
||||||
|
CreateDebugEventFd(#[source] std::io::Error),
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "kvm",
|
feature = "kvm",
|
||||||
error("Failed to open hypervisor interface (is /dev/kvm available?): {0}")
|
error("Failed to open hypervisor interface (is /dev/kvm available?): {0}")
|
||||||
@@ -65,6 +68,12 @@ enum Error {
|
|||||||
BareEventMonitor,
|
BareEventMonitor,
|
||||||
#[error("Error doing event monitor I/O: {0}")]
|
#[error("Error doing event monitor I/O: {0}")]
|
||||||
EventMonitorIo(std::io::Error),
|
EventMonitorIo(std::io::Error),
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
#[error("Error parsing --gdb: {0}")]
|
||||||
|
ParsingGdb(option_parser::OptionParserError),
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
#[error("Error parsing --gdb: path required")]
|
||||||
|
BareGdb,
|
||||||
#[error("Error creating log file: {0}")]
|
#[error("Error creating log file: {0}")]
|
||||||
LogFileCreation(std::io::Error),
|
LogFileCreation(std::io::Error),
|
||||||
#[error("Error setting up logger: {0}")]
|
#[error("Error setting up logger: {0}")]
|
||||||
@@ -125,27 +134,22 @@ fn prepare_default_values() -> (String, String, String) {
|
|||||||
(default_vcpus, default_memory, default_rng)
|
(default_vcpus, default_memory, default_rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_app<'a, 'b>(
|
fn create_app<'a>(
|
||||||
default_vcpus: &'a str,
|
default_vcpus: &'a str,
|
||||||
default_memory: &'a str,
|
default_memory: &'a str,
|
||||||
default_rng: &'a str,
|
default_rng: &'a str,
|
||||||
) -> App<'a, 'b> {
|
) -> Command<'a> {
|
||||||
#[cfg(target_arch = "x86_64")]
|
let app = Command::new("cloud-hypervisor")
|
||||||
let mut app: App;
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
let app: App;
|
|
||||||
|
|
||||||
app = App::new("cloud-hypervisor")
|
|
||||||
// 'BUILT_VERSION' is set by the build script 'build.rs' at
|
// 'BUILT_VERSION' is set by the build script 'build.rs' at
|
||||||
// compile time
|
// compile time
|
||||||
.version(env!("BUILT_VERSION"))
|
.version(env!("BUILT_VERSION"))
|
||||||
.author(crate_authors!())
|
.author(crate_authors!())
|
||||||
.about("Launch a cloud-hypervisor VMM.")
|
.about("Launch a cloud-hypervisor VMM.")
|
||||||
.group(ArgGroup::with_name("vm-config").multiple(true))
|
.group(ArgGroup::new("vm-config").multiple(true))
|
||||||
.group(ArgGroup::with_name("vmm-config").multiple(true))
|
.group(ArgGroup::new("vmm-config").multiple(true))
|
||||||
.group(ArgGroup::with_name("logging").multiple(true))
|
.group(ArgGroup::new("logging").multiple(true))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("cpus")
|
Arg::new("cpus")
|
||||||
.long("cpus")
|
.long("cpus")
|
||||||
.help(
|
.help(
|
||||||
"boot=<boot_vcpus>,max=<max_vcpus>,\
|
"boot=<boot_vcpus>,max=<max_vcpus>,\
|
||||||
@@ -157,16 +161,16 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("platform")
|
Arg::new("platform")
|
||||||
.long("platform")
|
.long("platform")
|
||||||
.help(
|
.help(
|
||||||
"num_pci_segments=<num pci segments>",
|
"num_pci_segments=<num pci segments>,iommu_segments=<list_of_segments>",
|
||||||
)
|
)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("memory")
|
Arg::new("memory")
|
||||||
.long("memory")
|
.long("memory")
|
||||||
.help(
|
.help(
|
||||||
"Memory parameters \
|
"Memory parameters \
|
||||||
@@ -181,7 +185,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("memory-zone")
|
Arg::new("memory-zone")
|
||||||
.long("memory-zone")
|
.long("memory-zone")
|
||||||
.help(
|
.help(
|
||||||
"User defined memory zone parameters \
|
"User defined memory zone parameters \
|
||||||
@@ -198,7 +202,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("kernel")
|
Arg::new("kernel")
|
||||||
.long("kernel")
|
.long("kernel")
|
||||||
.help(
|
.help(
|
||||||
"Path to loaded kernel. This may be a kernel or firmware that supports a PVH \
|
"Path to loaded kernel. This may be a kernel or firmware that supports a PVH \
|
||||||
@@ -208,21 +212,21 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("initramfs")
|
Arg::new("initramfs")
|
||||||
.long("initramfs")
|
.long("initramfs")
|
||||||
.help("Path to initramfs image")
|
.help("Path to initramfs image")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("cmdline")
|
Arg::new("cmdline")
|
||||||
.long("cmdline")
|
.long("cmdline")
|
||||||
.help("Kernel command line")
|
.help("Kernel command line")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("disk")
|
Arg::new("disk")
|
||||||
.long("disk")
|
.long("disk")
|
||||||
.help(config::DiskConfig::SYNTAX)
|
.help(config::DiskConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -230,7 +234,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("net")
|
Arg::new("net")
|
||||||
.long("net")
|
.long("net")
|
||||||
.help(config::NetConfig::SYNTAX)
|
.help(config::NetConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -238,7 +242,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("rng")
|
Arg::new("rng")
|
||||||
.long("rng")
|
.long("rng")
|
||||||
.help(
|
.help(
|
||||||
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
|
"Random number generator parameters \"src=<entropy_source_path>,iommu=on|off\"",
|
||||||
@@ -247,14 +251,14 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("balloon")
|
Arg::new("balloon")
|
||||||
.long("balloon")
|
.long("balloon")
|
||||||
.help(config::BalloonConfig::SYNTAX)
|
.help(config::BalloonConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("fs")
|
Arg::new("fs")
|
||||||
.long("fs")
|
.long("fs")
|
||||||
.help(config::FsConfig::SYNTAX)
|
.help(config::FsConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -262,7 +266,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("pmem")
|
Arg::new("pmem")
|
||||||
.long("pmem")
|
.long("pmem")
|
||||||
.help(config::PmemConfig::SYNTAX)
|
.help(config::PmemConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -270,14 +274,14 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("serial")
|
Arg::new("serial")
|
||||||
.long("serial")
|
.long("serial")
|
||||||
.help("Control serial port: off|null|pty|tty|file=/path/to/a/file")
|
.help("Control serial port: off|null|pty|tty|file=/path/to/a/file")
|
||||||
.default_value("null")
|
.default_value("null")
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("console")
|
Arg::new("console")
|
||||||
.long("console")
|
.long("console")
|
||||||
.help(
|
.help(
|
||||||
"Control (virtio) console: \"off|null|pty|tty|file=/path/to/a/file,iommu=on|off\"",
|
"Control (virtio) console: \"off|null|pty|tty|file=/path/to/a/file,iommu=on|off\"",
|
||||||
@@ -286,7 +290,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("device")
|
Arg::new("device")
|
||||||
.long("device")
|
.long("device")
|
||||||
.help(config::DeviceConfig::SYNTAX)
|
.help(config::DeviceConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -294,7 +298,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("user-device")
|
Arg::new("user-device")
|
||||||
.long("user-device")
|
.long("user-device")
|
||||||
.help(config::UserDeviceConfig::SYNTAX)
|
.help(config::UserDeviceConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -302,7 +306,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("vsock")
|
Arg::new("vsock")
|
||||||
.long("vsock")
|
.long("vsock")
|
||||||
.help(config::VsockConfig::SYNTAX)
|
.help(config::VsockConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -310,7 +314,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("numa")
|
Arg::new("numa")
|
||||||
.long("numa")
|
.long("numa")
|
||||||
.help(config::NumaConfig::SYNTAX)
|
.help(config::NumaConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -318,21 +322,21 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("watchdog")
|
Arg::new("watchdog")
|
||||||
.long("watchdog")
|
.long("watchdog")
|
||||||
.help("Enable virtio-watchdog")
|
.help("Enable virtio-watchdog")
|
||||||
.takes_value(false)
|
.takes_value(false)
|
||||||
.group("vm-config"),
|
.group("vm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("v")
|
Arg::new("v")
|
||||||
.short("v")
|
.short('v')
|
||||||
.multiple(true)
|
.multiple_occurrences(true)
|
||||||
.help("Sets the level of debugging output")
|
.help("Sets the level of debugging output")
|
||||||
.group("logging"),
|
.group("logging"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("log-file")
|
Arg::new("log-file")
|
||||||
.long("log-file")
|
.long("log-file")
|
||||||
.help("Log file. Standard error is used if not specified")
|
.help("Log file. Standard error is used if not specified")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -340,7 +344,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("logging"),
|
.group("logging"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("api-socket")
|
Arg::new("api-socket")
|
||||||
.long("api-socket")
|
.long("api-socket")
|
||||||
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
|
.help("HTTP API socket (UNIX domain socket): path=</path/to/a/file> or fd=<fd>.")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -348,7 +352,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vmm-config"),
|
.group("vmm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("event-monitor")
|
Arg::new("event-monitor")
|
||||||
.long("event-monitor")
|
.long("event-monitor")
|
||||||
.help("File to report events on: path=</path/to/a/file> or fd=<fd>")
|
.help("File to report events on: path=</path/to/a/file> or fd=<fd>")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -356,7 +360,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vmm-config"),
|
.group("vmm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("restore")
|
Arg::new("restore")
|
||||||
.long("restore")
|
.long("restore")
|
||||||
.help(config::RestoreConfig::SYNTAX)
|
.help(config::RestoreConfig::SYNTAX)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
@@ -364,7 +368,7 @@ fn create_app<'a, 'b>(
|
|||||||
.group("vmm-config"),
|
.group("vmm-config"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("seccomp")
|
Arg::new("seccomp")
|
||||||
.long("seccomp")
|
.long("seccomp")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(&["true", "false", "log"])
|
.possible_values(&["true", "false", "log"])
|
||||||
@@ -372,27 +376,32 @@ fn create_app<'a, 'b>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
{
|
let app = app.arg(
|
||||||
app = app.arg(
|
Arg::new("sgx-epc")
|
||||||
Arg::with_name("sgx-epc")
|
.long("sgx-epc")
|
||||||
.long("sgx-epc")
|
.help(config::SgxEpcConfig::SYNTAX)
|
||||||
.help(config::SgxEpcConfig::SYNTAX)
|
.takes_value(true)
|
||||||
.takes_value(true)
|
.min_values(1)
|
||||||
.min_values(1)
|
.group("vm-config"),
|
||||||
.group("vm-config"),
|
);
|
||||||
);
|
|
||||||
}
|
#[cfg(feature = "gdb")]
|
||||||
|
let app = app.arg(
|
||||||
|
Arg::new("gdb")
|
||||||
|
.long("gdb")
|
||||||
|
.help("GDB socket (UNIX domain socket): path=</path/to/a/file>")
|
||||||
|
.takes_value(true)
|
||||||
|
.group("vmm-config"),
|
||||||
|
);
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
{
|
let app = app.arg(
|
||||||
app = app.arg(
|
Arg::new("tdx")
|
||||||
Arg::with_name("tdx")
|
.long("tdx")
|
||||||
.long("tdx")
|
.help("TDX Support: firmware=<tdvf path>")
|
||||||
.help("TDX Support: firmware=<tdvf path>")
|
.takes_value(true)
|
||||||
.takes_value(true)
|
.group("vm-config"),
|
||||||
.group("vm-config"),
|
);
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
@@ -513,8 +522,8 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
|||||||
// Before we start any threads, mask the signals we'll be
|
// Before we start any threads, mask the signals we'll be
|
||||||
// installing handlers for, to make sure they only ever run on the
|
// installing handlers for, to make sure they only ever run on the
|
||||||
// dedicated signal handling thread we'll start in a bit.
|
// dedicated signal handling thread we'll start in a bit.
|
||||||
for sig in vmm::vm::HANDLED_SIGNALS {
|
for sig in &vmm::vm::HANDLED_SIGNALS {
|
||||||
if let Err(e) = block_signal(sig) {
|
if let Err(e) = block_signal(*sig) {
|
||||||
eprintln!("Error blocking signals: {}", e);
|
eprintln!("Error blocking signals: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -522,6 +531,26 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
|||||||
event!("vmm", "starting");
|
event!("vmm", "starting");
|
||||||
|
|
||||||
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
|
let hypervisor = hypervisor::new().map_err(Error::CreateHypervisor)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
let gdb_socket_path = if let Some(gdb_config) = cmd_arguments.value_of("gdb") {
|
||||||
|
let mut parser = OptionParser::new();
|
||||||
|
parser.add("path");
|
||||||
|
parser.parse(gdb_config).map_err(Error::ParsingGdb)?;
|
||||||
|
|
||||||
|
if parser.is_set("path") {
|
||||||
|
Some(std::path::PathBuf::from(parser.get("path").unwrap()))
|
||||||
|
} else {
|
||||||
|
return Err(Error::BareGdb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
let debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
let vm_debug_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::CreateDebugEventFd)?;
|
||||||
|
|
||||||
let vmm_thread = vmm::start_vmm_thread(
|
let vmm_thread = vmm::start_vmm_thread(
|
||||||
env!("CARGO_PKG_VERSION").to_string(),
|
env!("CARGO_PKG_VERSION").to_string(),
|
||||||
&api_socket_path,
|
&api_socket_path,
|
||||||
@@ -529,14 +558,27 @@ fn start_vmm(cmd_arguments: ArgMatches) -> Result<Option<String>, Error> {
|
|||||||
api_evt.try_clone().unwrap(),
|
api_evt.try_clone().unwrap(),
|
||||||
http_sender,
|
http_sender,
|
||||||
api_request_receiver,
|
api_request_receiver,
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
gdb_socket_path,
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
debug_evt.try_clone().unwrap(),
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
vm_debug_evt.try_clone().unwrap(),
|
||||||
&seccomp_action,
|
&seccomp_action,
|
||||||
hypervisor,
|
hypervisor,
|
||||||
)
|
)
|
||||||
.map_err(Error::StartVmmThread)?;
|
.map_err(Error::StartVmmThread)?;
|
||||||
|
|
||||||
// Can't test for "vm-config" group as some have default values. The kernel
|
// Can't test for "vm-config" group as some have default values. The kernel (or tdx if enabled)
|
||||||
// is the only required option for booting the VM.
|
// is the only required option for booting the VM.
|
||||||
if cmd_arguments.is_present("kernel") || cmd_arguments.is_present("tdx") {
|
#[cfg(feature = "tdx")]
|
||||||
|
let tdx_or_kernel_present =
|
||||||
|
cmd_arguments.is_present("kernel") || cmd_arguments.is_present("tdx");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "tdx"))]
|
||||||
|
let tdx_or_kernel_present = cmd_arguments.is_present("kernel");
|
||||||
|
|
||||||
|
if tdx_or_kernel_present {
|
||||||
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments);
|
let vm_params = config::VmParams::from_arg_matches(&cmd_arguments);
|
||||||
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
let vm_config = config::VmConfig::parse(vm_params).map_err(Error::ParsingConfig)?;
|
||||||
|
|
||||||
@@ -586,10 +628,6 @@ fn main() {
|
|||||||
std::process::exit(exit_code);
|
std::process::exit(exit_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate credibility;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod unit_tests {
|
mod unit_tests {
|
||||||
use crate::config::HotplugMethod;
|
use crate::config::HotplugMethod;
|
||||||
@@ -618,15 +656,11 @@ mod unit_tests {
|
|||||||
let cli_vm_config = get_vm_config_from_vec(cli);
|
let cli_vm_config = get_vm_config_from_vec(cli);
|
||||||
let openapi_vm_config: VmConfig = serde_json::from_str(openapi).unwrap();
|
let openapi_vm_config: VmConfig = serde_json::from_str(openapi).unwrap();
|
||||||
|
|
||||||
test_block!(tb, "", {
|
if equal {
|
||||||
if equal {
|
assert_eq!(cli_vm_config, openapi_vm_config);
|
||||||
aver_eq!(tb, cli_vm_config, openapi_vm_config);
|
} else {
|
||||||
} else {
|
assert_ne!(cli_vm_config, openapi_vm_config);
|
||||||
aver_ne!(tb, cli_vm_config, openapi_vm_config);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
(cli_vm_config, openapi_vm_config)
|
(cli_vm_config, openapi_vm_config)
|
||||||
}
|
}
|
||||||
@@ -640,70 +674,69 @@ mod unit_tests {
|
|||||||
let (result_vm_config, _) = compare_vm_config_cli_vs_json(&cli, openapi, true);
|
let (result_vm_config, _) = compare_vm_config_cli_vs_json(&cli, openapi, true);
|
||||||
|
|
||||||
// As a second step, we validate all the default values.
|
// As a second step, we validate all the default values.
|
||||||
test_block!(tb, "", {
|
let expected_vm_config = VmConfig {
|
||||||
let expected_vm_config = VmConfig {
|
cpus: CpusConfig {
|
||||||
cpus: CpusConfig {
|
boot_vcpus: 1,
|
||||||
boot_vcpus: 1,
|
max_vcpus: 1,
|
||||||
max_vcpus: 1,
|
topology: None,
|
||||||
topology: None,
|
kvm_hyperv: false,
|
||||||
kvm_hyperv: false,
|
max_phys_bits: 46,
|
||||||
max_phys_bits: 46,
|
affinity: None,
|
||||||
affinity: None,
|
},
|
||||||
},
|
memory: MemoryConfig {
|
||||||
memory: MemoryConfig {
|
size: 536_870_912,
|
||||||
size: 536_870_912,
|
mergeable: false,
|
||||||
mergeable: false,
|
hotplug_method: HotplugMethod::Acpi,
|
||||||
hotplug_method: HotplugMethod::Acpi,
|
hotplug_size: None,
|
||||||
hotplug_size: None,
|
hotplugged_size: None,
|
||||||
hotplugged_size: None,
|
shared: false,
|
||||||
shared: false,
|
hugepages: false,
|
||||||
hugepages: false,
|
hugepage_size: None,
|
||||||
hugepage_size: None,
|
prefault: false,
|
||||||
prefault: false,
|
zones: None,
|
||||||
zones: None,
|
},
|
||||||
},
|
kernel: Some(KernelConfig {
|
||||||
kernel: Some(KernelConfig {
|
path: PathBuf::from("/path/to/kernel"),
|
||||||
path: PathBuf::from("/path/to/kernel"),
|
}),
|
||||||
}),
|
initramfs: None,
|
||||||
initramfs: None,
|
cmdline: CmdlineConfig {
|
||||||
cmdline: CmdlineConfig {
|
args: String::from(""),
|
||||||
args: String::from(""),
|
},
|
||||||
},
|
disks: None,
|
||||||
disks: None,
|
net: None,
|
||||||
net: None,
|
rng: RngConfig {
|
||||||
rng: RngConfig {
|
src: PathBuf::from("/dev/urandom"),
|
||||||
src: PathBuf::from("/dev/urandom"),
|
|
||||||
iommu: false,
|
|
||||||
},
|
|
||||||
balloon: None,
|
|
||||||
fs: None,
|
|
||||||
pmem: None,
|
|
||||||
serial: ConsoleConfig {
|
|
||||||
file: None,
|
|
||||||
mode: ConsoleOutputMode::Null,
|
|
||||||
iommu: false,
|
|
||||||
},
|
|
||||||
console: ConsoleConfig {
|
|
||||||
file: None,
|
|
||||||
mode: ConsoleOutputMode::Tty,
|
|
||||||
iommu: false,
|
|
||||||
},
|
|
||||||
devices: None,
|
|
||||||
user_devices: None,
|
|
||||||
vsock: None,
|
|
||||||
iommu: false,
|
iommu: false,
|
||||||
#[cfg(target_arch = "x86_64")]
|
},
|
||||||
sgx_epc: None,
|
balloon: None,
|
||||||
numa: None,
|
fs: None,
|
||||||
watchdog: false,
|
pmem: None,
|
||||||
#[cfg(feature = "tdx")]
|
serial: ConsoleConfig {
|
||||||
tdx: None,
|
file: None,
|
||||||
platform: None,
|
mode: ConsoleOutputMode::Null,
|
||||||
};
|
iommu: false,
|
||||||
|
},
|
||||||
|
console: ConsoleConfig {
|
||||||
|
file: None,
|
||||||
|
mode: ConsoleOutputMode::Tty,
|
||||||
|
iommu: false,
|
||||||
|
},
|
||||||
|
devices: None,
|
||||||
|
user_devices: None,
|
||||||
|
vsock: None,
|
||||||
|
iommu: false,
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
sgx_epc: None,
|
||||||
|
numa: None,
|
||||||
|
watchdog: false,
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
tdx: None,
|
||||||
|
#[cfg(feature = "gdb")]
|
||||||
|
gdb: false,
|
||||||
|
platform: None,
|
||||||
|
};
|
||||||
|
|
||||||
aver_eq!(tb, expected_vm_config, result_vm_config);
|
assert_eq!(expected_vm_config, result_vm_config);
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "3.0.1"
|
dirs = "4.0.0"
|
||||||
epoll = "4.3.1"
|
epoll = "4.3.1"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
libc = "0.2.91"
|
libc = "0.2.91"
|
||||||
ssh2 = "0.9.1"
|
ssh2 = { version = "0.9.1", features = ["vendored-openssl"]}
|
||||||
vmm-sys-util = "0.9.0"
|
vmm-sys-util = "0.9.0"
|
||||||
wait-timeout = "0.2.0"
|
wait-timeout = "0.2.0"
|
||||||
|
|||||||
@@ -3,20 +3,38 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
use ssh2::Session;
|
use ssh2::Session;
|
||||||
|
use std::env;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use std::net::TcpStream;
|
use std::net::TcpStream;
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{ExitStatus, Output};
|
use std::process::{Child, Command, ExitStatus, Output, Stdio};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use vmm_sys_util::tempdir::TempDir;
|
use vmm_sys_util::tempdir::TempDir;
|
||||||
|
|
||||||
pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted";
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Parsing(std::num::ParseIntError),
|
||||||
|
SshCommand(SshCommandError),
|
||||||
|
WaitForBoot(WaitForBootError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SshCommandError> for Error {
|
||||||
|
fn from(e: SshCommandError) -> Self {
|
||||||
|
Self::SshCommand(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct GuestNetworkConfig {
|
pub struct GuestNetworkConfig {
|
||||||
pub guest_ip: String,
|
pub guest_ip: String,
|
||||||
@@ -31,6 +49,7 @@ pub struct GuestNetworkConfig {
|
|||||||
pub tcp_listener_port: u16,
|
pub tcp_listener_port: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const DEFAULT_TCP_LISTENER_MESSAGE: &str = "booted";
|
||||||
pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000;
|
pub const DEFAULT_TCP_LISTENER_PORT: u16 = 8000;
|
||||||
pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 80;
|
pub const DEFAULT_TCP_LISTENER_TIMEOUT: i32 = 80;
|
||||||
|
|
||||||
@@ -138,6 +157,7 @@ pub trait DiskConfig {
|
|||||||
fn disk(&self, disk_type: DiskType) -> Option<String>;
|
fn disk(&self, disk_type: DiskType) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct UbuntuDiskConfig {
|
pub struct UbuntuDiskConfig {
|
||||||
osdisk_path: String,
|
osdisk_path: String,
|
||||||
cloudinit_path: String,
|
cloudinit_path: String,
|
||||||
@@ -506,6 +526,100 @@ pub enum SshCommandError {
|
|||||||
Command(ssh2::Error),
|
Command(ssh2::Error),
|
||||||
ExitStatus(ssh2::Error),
|
ExitStatus(ssh2::Error),
|
||||||
NonZeroExitStatus(i32),
|
NonZeroExitStatus(i32),
|
||||||
|
FileRead(std::io::Error),
|
||||||
|
FileMetadata(std::io::Error),
|
||||||
|
ScpSend(ssh2::Error),
|
||||||
|
WriteAll(std::io::Error),
|
||||||
|
SendEof(ssh2::Error),
|
||||||
|
WaitEof(ssh2::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scp_to_guest_with_auth(
|
||||||
|
path: &Path,
|
||||||
|
remote_path: &Path,
|
||||||
|
auth: &PasswordAuth,
|
||||||
|
ip: &str,
|
||||||
|
retries: u8,
|
||||||
|
timeout: u8,
|
||||||
|
) -> Result<(), SshCommandError> {
|
||||||
|
let mut counter = 0;
|
||||||
|
loop {
|
||||||
|
match (|| -> Result<(), SshCommandError> {
|
||||||
|
let tcp =
|
||||||
|
TcpStream::connect(format!("{}:22", ip)).map_err(SshCommandError::Connection)?;
|
||||||
|
let mut sess = Session::new().unwrap();
|
||||||
|
sess.set_tcp_stream(tcp);
|
||||||
|
sess.handshake().map_err(SshCommandError::Handshake)?;
|
||||||
|
|
||||||
|
sess.userauth_password(&auth.username, &auth.password)
|
||||||
|
.map_err(SshCommandError::Authentication)?;
|
||||||
|
assert!(sess.authenticated());
|
||||||
|
|
||||||
|
let content = fs::read(path).map_err(SshCommandError::FileRead)?;
|
||||||
|
let mode = fs::metadata(path)
|
||||||
|
.map_err(SshCommandError::FileMetadata)?
|
||||||
|
.permissions()
|
||||||
|
.mode()
|
||||||
|
& 0o777;
|
||||||
|
|
||||||
|
let mut channel = sess
|
||||||
|
.scp_send(remote_path, mode as i32, content.len() as u64, None)
|
||||||
|
.map_err(SshCommandError::ScpSend)?;
|
||||||
|
channel
|
||||||
|
.write_all(&content)
|
||||||
|
.map_err(SshCommandError::WriteAll)?;
|
||||||
|
channel.send_eof().map_err(SshCommandError::SendEof)?;
|
||||||
|
channel.wait_eof().map_err(SshCommandError::WaitEof)?;
|
||||||
|
|
||||||
|
// Intentionally ignore these results here as their failure
|
||||||
|
// does not precipitate a repeat
|
||||||
|
let _ = channel.close();
|
||||||
|
let _ = channel.wait_close();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})() {
|
||||||
|
Ok(_) => break,
|
||||||
|
Err(e) => {
|
||||||
|
counter += 1;
|
||||||
|
if counter >= retries {
|
||||||
|
eprintln!(
|
||||||
|
"\n\n==== Start scp command output (FAILED) ====\n\n\
|
||||||
|
path =\"{:?}\"\n\
|
||||||
|
remote_path =\"{:?}\"\n\
|
||||||
|
auth=\"{:#?}\"\n\
|
||||||
|
ip=\"{}\"\n\
|
||||||
|
error=\"{:?}\"\n\
|
||||||
|
\n==== End scp command outout ====\n\n",
|
||||||
|
path, remote_path, auth, ip, e
|
||||||
|
);
|
||||||
|
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
thread::sleep(std::time::Duration::new((timeout * counter).into(), 0));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scp_to_guest(
|
||||||
|
path: &Path,
|
||||||
|
remote_path: &Path,
|
||||||
|
ip: &str,
|
||||||
|
retries: u8,
|
||||||
|
timeout: u8,
|
||||||
|
) -> Result<(), SshCommandError> {
|
||||||
|
scp_to_guest_with_auth(
|
||||||
|
path,
|
||||||
|
remote_path,
|
||||||
|
&PasswordAuth {
|
||||||
|
username: String::from("cloud"),
|
||||||
|
password: String::from("cloud123"),
|
||||||
|
},
|
||||||
|
ip,
|
||||||
|
retries,
|
||||||
|
timeout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ssh_command_ip_with_auth(
|
pub fn ssh_command_ip_with_auth(
|
||||||
@@ -604,3 +718,587 @@ pub fn exec_host_command_output(command: &str) -> Output {
|
|||||||
.output()
|
.output()
|
||||||
.unwrap_or_else(|_| panic!("Expected '{}' to run", command))
|
.unwrap_or_else(|_| panic!("Expected '{}' to run", command))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const PIPE_SIZE: i32 = 32 << 20;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref NEXT_VM_ID: Mutex<u8> = Mutex::new(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Guest {
|
||||||
|
pub tmp_dir: TempDir,
|
||||||
|
pub disk_config: Box<dyn DiskConfig>,
|
||||||
|
pub network: GuestNetworkConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safe to implement as we know we have no interior mutability
|
||||||
|
impl std::panic::RefUnwindSafe for Guest {}
|
||||||
|
|
||||||
|
impl Guest {
|
||||||
|
pub fn new_from_ip_range(mut disk_config: Box<dyn DiskConfig>, class: &str, id: u8) -> Self {
|
||||||
|
let tmp_dir = TempDir::new_with_prefix("/tmp/ch").unwrap();
|
||||||
|
|
||||||
|
let network = GuestNetworkConfig {
|
||||||
|
guest_ip: format!("{}.{}.2", class, id),
|
||||||
|
l2_guest_ip1: format!("{}.{}.3", class, id),
|
||||||
|
l2_guest_ip2: format!("{}.{}.4", class, id),
|
||||||
|
l2_guest_ip3: format!("{}.{}.5", class, id),
|
||||||
|
host_ip: format!("{}.{}.1", class, id),
|
||||||
|
guest_mac: format!("12:34:56:78:90:{:02x}", id),
|
||||||
|
l2_guest_mac1: format!("de:ad:be:ef:12:{:02x}", id),
|
||||||
|
l2_guest_mac2: format!("de:ad:be:ef:34:{:02x}", id),
|
||||||
|
l2_guest_mac3: format!("de:ad:be:ef:56:{:02x}", id),
|
||||||
|
tcp_listener_port: DEFAULT_TCP_LISTENER_PORT + id as u16,
|
||||||
|
};
|
||||||
|
|
||||||
|
disk_config.prepare_files(&tmp_dir, &network);
|
||||||
|
|
||||||
|
Guest {
|
||||||
|
tmp_dir,
|
||||||
|
disk_config,
|
||||||
|
network,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(disk_config: Box<dyn DiskConfig>) -> Self {
|
||||||
|
let mut guard = NEXT_VM_ID.lock().unwrap();
|
||||||
|
let id = *guard;
|
||||||
|
*guard = id + 1;
|
||||||
|
|
||||||
|
Self::new_from_ip_range(disk_config, "192.168", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_net_string(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"tap=,mac={},ip={},mask=255.255.255.0",
|
||||||
|
self.network.guest_mac, self.network.host_ip
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_net_string_w_iommu(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"tap=,mac={},ip={},mask=255.255.255.0,iommu=on",
|
||||||
|
self.network.guest_mac, self.network.host_ip
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ssh_command(&self, command: &str) -> Result<String, SshCommandError> {
|
||||||
|
ssh_command_ip(
|
||||||
|
command,
|
||||||
|
&self.network.guest_ip,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn ssh_command_l1(&self, command: &str) -> Result<String, SshCommandError> {
|
||||||
|
ssh_command_ip(
|
||||||
|
command,
|
||||||
|
&self.network.guest_ip,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn ssh_command_l2_1(&self, command: &str) -> Result<String, SshCommandError> {
|
||||||
|
ssh_command_ip(
|
||||||
|
command,
|
||||||
|
&self.network.l2_guest_ip1,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn ssh_command_l2_2(&self, command: &str) -> Result<String, SshCommandError> {
|
||||||
|
ssh_command_ip(
|
||||||
|
command,
|
||||||
|
&self.network.l2_guest_ip2,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn ssh_command_l2_3(&self, command: &str) -> Result<String, SshCommandError> {
|
||||||
|
ssh_command_ip(
|
||||||
|
command,
|
||||||
|
&self.network.l2_guest_ip3,
|
||||||
|
DEFAULT_SSH_RETRIES,
|
||||||
|
DEFAULT_SSH_TIMEOUT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn api_create_body(
|
||||||
|
&self,
|
||||||
|
cpu_count: u8,
|
||||||
|
_fw_path: &str,
|
||||||
|
_kernel_path: &str,
|
||||||
|
_kernel_cmd: &str,
|
||||||
|
) -> String {
|
||||||
|
#[cfg(all(target_arch = "x86_64", not(feature = "mshv")))]
|
||||||
|
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
|
||||||
|
cpu_count,
|
||||||
|
cpu_count,
|
||||||
|
_fw_path,
|
||||||
|
self.network.host_ip,
|
||||||
|
self.network.guest_mac,
|
||||||
|
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
|
||||||
|
self.disk_config.disk(DiskType::CloudInit).unwrap().as_str(),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_arch = "aarch64", feature = "mshv"))]
|
||||||
|
format! {"{{\"cpus\":{{\"boot_vcpus\":{},\"max_vcpus\":{}}},\"kernel\":{{\"path\":\"{}\"}},\"cmdline\":{{\"args\": \"{}\"}},\"net\":[{{\"ip\":\"{}\", \"mask\":\"255.255.255.0\", \"mac\":\"{}\"}}], \"disks\":[{{\"path\":\"{}\"}}, {{\"path\":\"{}\"}}]}}",
|
||||||
|
cpu_count,
|
||||||
|
cpu_count,
|
||||||
|
_kernel_path,
|
||||||
|
_kernel_cmd,
|
||||||
|
self.network.host_ip,
|
||||||
|
self.network.guest_mac,
|
||||||
|
self.disk_config.disk(DiskType::OperatingSystem).unwrap().as_str(),
|
||||||
|
self.disk_config.disk(DiskType::CloudInit).unwrap().as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_cpu_count(&self) -> Result<u32, Error> {
|
||||||
|
self.ssh_command("grep -c processor /proc/cpuinfo")?
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.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()
|
||||||
|
.parse()
|
||||||
|
.map_err(Error::Parsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn get_total_memory_l2(&self) -> Result<u32, Error> {
|
||||||
|
self.ssh_command_l2_1("grep MemTotal /proc/meminfo | grep -o \"[0-9]*\"")?
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.map_err(Error::Parsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_numa_node_memory(&self, node_id: usize) -> Result<u32, Error> {
|
||||||
|
self.ssh_command(
|
||||||
|
format!(
|
||||||
|
"grep MemTotal /sys/devices/system/node/node{}/meminfo \
|
||||||
|
| cut -d \":\" -f 2 | grep -o \"[0-9]*\"",
|
||||||
|
node_id
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
)?
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.map_err(Error::Parsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_vm_boot(&self, custom_timeout: Option<i32>) -> Result<(), Error> {
|
||||||
|
self.network
|
||||||
|
.wait_vm_boot(custom_timeout)
|
||||||
|
.map_err(Error::WaitForBoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_numa_node_cpus(&self, node_id: usize, cpus: Vec<usize>) -> Result<(), Error> {
|
||||||
|
for cpu in cpus.iter() {
|
||||||
|
let cmd = format!(
|
||||||
|
"[ -d \"/sys/devices/system/node/node{}/cpu{}\" ]",
|
||||||
|
node_id, cpu
|
||||||
|
);
|
||||||
|
self.ssh_command(cmd.as_str())?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_numa_node_distances(
|
||||||
|
&self,
|
||||||
|
node_id: usize,
|
||||||
|
distances: &str,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
let cmd = format!("cat /sys/devices/system/node/node{}/distance", node_id);
|
||||||
|
if self.ssh_command(cmd.as_str())?.trim() == distances {
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_numa_common(
|
||||||
|
&self,
|
||||||
|
mem_ref: Option<&[u32]>,
|
||||||
|
node_ref: Option<&[Vec<usize>]>,
|
||||||
|
distance_ref: Option<&[&str]>,
|
||||||
|
) {
|
||||||
|
if let Some(mem_ref) = mem_ref {
|
||||||
|
// Check each NUMA node has been assigned the right amount of
|
||||||
|
// memory.
|
||||||
|
for (i, &m) in mem_ref.iter().enumerate() {
|
||||||
|
assert!(self.get_numa_node_memory(i).unwrap_or_default() > m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(node_ref) = node_ref {
|
||||||
|
// Check each NUMA node has been assigned the right CPUs set.
|
||||||
|
for (i, n) in node_ref.iter().enumerate() {
|
||||||
|
self.check_numa_node_cpus(i, n.clone()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(distance_ref) = distance_ref {
|
||||||
|
// Check each NUMA node has been assigned the right distances.
|
||||||
|
for (i, &d) in distance_ref.iter().enumerate() {
|
||||||
|
assert!(self.check_numa_node_distances(i, d).unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn check_sgx_support(&self) -> Result<(), Error> {
|
||||||
|
self.ssh_command(
|
||||||
|
"cpuid -l 0x7 -s 0 | tr -s [:space:] | grep -q 'SGX: \
|
||||||
|
Software Guard Extensions supported = true'",
|
||||||
|
)?;
|
||||||
|
self.ssh_command(
|
||||||
|
"cpuid -l 0x7 -s 0 | tr -s [:space:] | grep -q 'SGX_LC: \
|
||||||
|
SGX launch config supported = true'",
|
||||||
|
)?;
|
||||||
|
self.ssh_command(
|
||||||
|
"cpuid -l 0x12 -s 0 | tr -s [:space:] | grep -q 'SGX1 \
|
||||||
|
supported = true'",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_entropy(&self) -> Result<u32, Error> {
|
||||||
|
self.ssh_command("cat /proc/sys/kernel/random/entropy_avail")?
|
||||||
|
.trim()
|
||||||
|
.parse()
|
||||||
|
.map_err(Error::Parsing)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pci_bridge_class(&self) -> Result<String, Error> {
|
||||||
|
Ok(self
|
||||||
|
.ssh_command("cat /sys/bus/pci/devices/0000:00:00.0/class")?
|
||||||
|
.trim()
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pci_device_ids(&self) -> Result<String, Error> {
|
||||||
|
Ok(self
|
||||||
|
.ssh_command("cat /sys/bus/pci/devices/*/device")?
|
||||||
|
.trim()
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pci_vendor_ids(&self) -> Result<String, Error> {
|
||||||
|
Ok(self
|
||||||
|
.ssh_command("cat /sys/bus/pci/devices/*/vendor")?
|
||||||
|
.trim()
|
||||||
|
.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn does_device_vendor_pair_match(
|
||||||
|
&self,
|
||||||
|
device_id: &str,
|
||||||
|
vendor_id: &str,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
// We are checking if console device's device id and vendor id pair matches
|
||||||
|
let devices = self.get_pci_device_ids()?;
|
||||||
|
let devices: Vec<&str> = devices.split('\n').collect();
|
||||||
|
let vendors = self.get_pci_vendor_ids()?;
|
||||||
|
let vendors: Vec<&str> = vendors.split('\n').collect();
|
||||||
|
|
||||||
|
for (index, d_id) in devices.iter().enumerate() {
|
||||||
|
if *d_id == device_id {
|
||||||
|
if let Some(v_id) = vendors.get(index) {
|
||||||
|
if *v_id == vendor_id {
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn valid_virtio_fs_cache_size(
|
||||||
|
&self,
|
||||||
|
dax: bool,
|
||||||
|
cache_size: Option<u64>,
|
||||||
|
) -> Result<bool, Error> {
|
||||||
|
// SHM region is called different things depending on kernel
|
||||||
|
let shm_region = self
|
||||||
|
.ssh_command("sudo grep 'virtio[0-9]\\|virtio-pci-shm' /proc/iomem || true")?
|
||||||
|
.trim()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
|
if shm_region.is_empty() {
|
||||||
|
return Ok(!dax);
|
||||||
|
}
|
||||||
|
|
||||||
|
// From this point, the region is not empty, hence it is an error
|
||||||
|
// if DAX is off.
|
||||||
|
if !dax {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cache = if let Some(cache) = cache_size {
|
||||||
|
cache
|
||||||
|
} else {
|
||||||
|
// 8Gib by default
|
||||||
|
0x0002_0000_0000
|
||||||
|
};
|
||||||
|
|
||||||
|
let args: Vec<&str> = shm_region.split(':').collect();
|
||||||
|
if args.is_empty() {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let args: Vec<&str> = args[0].trim().split('-').collect();
|
||||||
|
if args.len() != 2 {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_addr = u64::from_str_radix(args[0], 16).map_err(Error::Parsing)?;
|
||||||
|
let end_addr = u64::from_str_radix(args[1], 16).map_err(Error::Parsing)?;
|
||||||
|
|
||||||
|
Ok(cache == (end_addr - start_addr + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_vsock(&self, socket: &str) {
|
||||||
|
// Listen from guest on vsock CID=3 PORT=16
|
||||||
|
// SOCKET-LISTEN:<domain>:<protocol>:<local-address>
|
||||||
|
let guest_ip = self.network.guest_ip.clone();
|
||||||
|
let listen_socat = thread::spawn(move || {
|
||||||
|
ssh_command_ip("sudo socat - SOCKET-LISTEN:40:0:x00x00x10x00x00x00x03x00x00x00x00x00x00x00 > vsock_log", &guest_ip, DEFAULT_SSH_RETRIES, DEFAULT_SSH_TIMEOUT).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make sure socat is listening, which might take a few second on slow systems
|
||||||
|
thread::sleep(std::time::Duration::new(10, 0));
|
||||||
|
|
||||||
|
// Write something to vsock from the host
|
||||||
|
assert!(exec_host_command_status(&format!(
|
||||||
|
"echo -e \"CONNECT 16\\nHelloWorld!\" | socat - UNIX-CONNECT:{}",
|
||||||
|
socket
|
||||||
|
))
|
||||||
|
.success());
|
||||||
|
|
||||||
|
// Wait for the thread to terminate.
|
||||||
|
listen_socat.join().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command("cat vsock_log").unwrap().trim(),
|
||||||
|
"HelloWorld!"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
pub fn check_nvidia_gpu(&self) {
|
||||||
|
// Run CUDA sample to validate it can find the device
|
||||||
|
let device_query_result = self
|
||||||
|
.ssh_command("sudo /root/NVIDIA_CUDA-11.3_Samples/bin/x86_64/linux/release/deviceQuery")
|
||||||
|
.unwrap();
|
||||||
|
assert!(device_query_result.contains("Detected 1 CUDA Capable device"));
|
||||||
|
assert!(device_query_result.contains("Device 0: \"NVIDIA Tesla T4\""));
|
||||||
|
assert!(device_query_result.contains("Result = PASS"));
|
||||||
|
|
||||||
|
// Run NVIDIA DCGM Diagnostics to validate the device is functional
|
||||||
|
self.ssh_command("sudo nv-hostengine").unwrap();
|
||||||
|
|
||||||
|
assert!(self
|
||||||
|
.ssh_command("sudo dcgmi discovery -l")
|
||||||
|
.unwrap()
|
||||||
|
.contains("Name: NVIDIA Tesla T4"));
|
||||||
|
assert_eq!(
|
||||||
|
self.ssh_command("sudo dcgmi diag -r 'diagnostic' | grep Pass | wc -l")
|
||||||
|
.unwrap()
|
||||||
|
.trim(),
|
||||||
|
"10"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reboot_linux(&self, current_reboot_count: u32, custom_timeout: Option<i32>) {
|
||||||
|
let list_boots_cmd = "sudo journalctl --list-boots | wc -l";
|
||||||
|
let boot_count = self
|
||||||
|
.ssh_command(list_boots_cmd)
|
||||||
|
.unwrap()
|
||||||
|
.trim()
|
||||||
|
.parse::<u32>()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
assert_eq!(boot_count, current_reboot_count + 1);
|
||||||
|
self.ssh_command("sudo reboot").unwrap();
|
||||||
|
|
||||||
|
self.wait_vm_boot(custom_timeout).unwrap();
|
||||||
|
let boot_count = self
|
||||||
|
.ssh_command(list_boots_cmd)
|
||||||
|
.unwrap()
|
||||||
|
.trim()
|
||||||
|
.parse::<u32>()
|
||||||
|
.unwrap_or_default();
|
||||||
|
assert_eq!(boot_count, current_reboot_count + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_memory_hotplug(&self) {
|
||||||
|
self.ssh_command("echo online | sudo tee /sys/devices/system/memory/auto_online_blocks")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_devices_common(&self, socket: Option<&String>, console_text: Option<&String>) {
|
||||||
|
// Check block devices are readable
|
||||||
|
self.ssh_command("sudo dd if=/dev/vda of=/dev/null bs=1M iflag=direct count=1024")
|
||||||
|
.unwrap();
|
||||||
|
self.ssh_command("sudo dd if=/dev/vdb of=/dev/null bs=1M iflag=direct count=8")
|
||||||
|
.unwrap();
|
||||||
|
// Check if the rng device is readable
|
||||||
|
self.ssh_command("sudo head -c 1000 /dev/hwrng > /dev/null")
|
||||||
|
.unwrap();
|
||||||
|
// Check vsock
|
||||||
|
if let Some(socket) = socket {
|
||||||
|
self.check_vsock(socket.as_str());
|
||||||
|
}
|
||||||
|
// Check if the console is usable
|
||||||
|
if let Some(console_text) = console_text {
|
||||||
|
let console_cmd = format!("echo {} | sudo tee /dev/hvc0", console_text);
|
||||||
|
self.ssh_command(&console_cmd).unwrap();
|
||||||
|
}
|
||||||
|
// The net device is 'automatically' exercised through the above 'ssh' commands
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GuestCommand<'a> {
|
||||||
|
command: Command,
|
||||||
|
guest: &'a Guest,
|
||||||
|
capture_output: bool,
|
||||||
|
print_cmd: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> GuestCommand<'a> {
|
||||||
|
pub fn new(guest: &'a Guest) -> Self {
|
||||||
|
Self::new_with_binary_name(guest, "cloud-hypervisor")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_binary_name(guest: &'a Guest, binary_name: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
command: Command::new(clh_command(binary_name)),
|
||||||
|
guest,
|
||||||
|
capture_output: false,
|
||||||
|
print_cmd: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn capture_output(&mut self) -> &mut Self {
|
||||||
|
self.capture_output = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_print_cmd(&mut self, print_cmd: bool) -> &mut Self {
|
||||||
|
self.print_cmd = print_cmd;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn(&mut self) -> io::Result<Child> {
|
||||||
|
if self.print_cmd {
|
||||||
|
println!(
|
||||||
|
"\n\n==== Start cloud-hypervisor command-line ====\n\n\
|
||||||
|
{:?}\n\
|
||||||
|
\n==== End cloud-hypervisor command-line ====\n\n",
|
||||||
|
self.command
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.capture_output {
|
||||||
|
let child = self
|
||||||
|
.command
|
||||||
|
.arg("-v")
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let fd = child.stdout.as_ref().unwrap().as_raw_fd();
|
||||||
|
let pipesize = unsafe { libc::fcntl(fd, libc::F_SETPIPE_SZ, PIPE_SIZE) };
|
||||||
|
let fd = child.stderr.as_ref().unwrap().as_raw_fd();
|
||||||
|
let pipesize1 = unsafe { libc::fcntl(fd, libc::F_SETPIPE_SZ, PIPE_SIZE) };
|
||||||
|
|
||||||
|
if pipesize >= PIPE_SIZE && pipesize1 >= PIPE_SIZE {
|
||||||
|
Ok(child)
|
||||||
|
} else {
|
||||||
|
Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
"resizing pipe w/ 'fnctl' failed!",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.command.arg("-v").spawn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args<I, S>(&mut self, args: I) -> &mut Self
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = S>,
|
||||||
|
S: AsRef<OsStr>,
|
||||||
|
{
|
||||||
|
self.command.args(args);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_disks(&mut self) -> &mut Self {
|
||||||
|
if self.guest.disk_config.disk(DiskType::CloudInit).is_some() {
|
||||||
|
self.args(&[
|
||||||
|
"--disk",
|
||||||
|
format!(
|
||||||
|
"path={}",
|
||||||
|
self.guest
|
||||||
|
.disk_config
|
||||||
|
.disk(DiskType::OperatingSystem)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
format!(
|
||||||
|
"path={}",
|
||||||
|
self.guest.disk_config.disk(DiskType::CloudInit).unwrap()
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
self.args(&[
|
||||||
|
"--disk",
|
||||||
|
format!(
|
||||||
|
"path={}",
|
||||||
|
self.guest
|
||||||
|
.disk_config
|
||||||
|
.disk(DiskType::OperatingSystem)
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
.as_str(),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default_net(&mut self) -> &mut Self {
|
||||||
|
self.args(&["--net", self.guest.default_net_string().as_str()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clh_command(cmd: &str) -> String {
|
||||||
|
env::var("BUILD_TARGET").map_or(
|
||||||
|
format!("target/x86_64-unknown-linux-gnu/release/{}", cmd),
|
||||||
|
|target| format!("target/{}/release/{}", target, cmd),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
14308
tests/integration.rs
14308
tests/integration.rs
File diff suppressed because it is too large
Load Diff
@@ -5,16 +5,16 @@ authors = ["The Cloud Hypervisor Authors"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.51"
|
anyhow = "1.0.55"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||||
serde_derive = ">=1.0.27"
|
serde_derive = ">=1.0.27"
|
||||||
serde_json = ">=1.0.9"
|
serde_json = ">=1.0.9"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-mmap", "backend-atomic"] }
|
vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] }
|
||||||
vmm-sys-util = ">=0.3.1"
|
vmm-sys-util = ">=0.3.1"
|
||||||
|
|
||||||
[dependencies.vfio-bindings]
|
[dependencies.vfio-bindings]
|
||||||
version = "0.2.0"
|
version = "0.3.1"
|
||||||
features = ["fam-wrappers"]
|
features = ["fam-wrappers"]
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ license = "Apache-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.4.3"
|
byteorder = "1.4.3"
|
||||||
crc32c = "0.6.0"
|
crc32c = "0.6.1"
|
||||||
libc = "0.2.108"
|
libc = "0.2.119"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
remain = "0.2.2"
|
remain = "0.2.2"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "vhost_user_backend"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["The Cloud Hypervisor Authors"]
|
|
||||||
edition = "2018"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
epoll = "4.3.1"
|
|
||||||
libc = "0.2.108"
|
|
||||||
log = "0.4.14"
|
|
||||||
virtio-bindings = "0.1.0"
|
|
||||||
virtio-queue = { path = "../virtio-queue" }
|
|
||||||
vm-memory = { version = "0.6.0", features = ["backend-bitmap"] }
|
|
||||||
vm-virtio = { path = "../vm-virtio" }
|
|
||||||
vmm-sys-util = "0.9.0"
|
|
||||||
vhost = { version = "0.2.0", features = ["vhost-user-slave"] }
|
|
||||||
@@ -1,960 +0,0 @@
|
|||||||
// Copyright 2019 Intel Corporation. All Rights Reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// Copyright 2019 Alibaba Cloud Computing. All rights reserved.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate log;
|
|
||||||
|
|
||||||
use std::error;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io;
|
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
|
||||||
use std::result;
|
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
|
||||||
use std::thread;
|
|
||||||
use vhost::vhost_user::message::{
|
|
||||||
VhostUserConfigFlags, VhostUserInflight, VhostUserMemoryRegion, VhostUserProtocolFeatures,
|
|
||||||
VhostUserSingleMemoryRegion, VhostUserVirtioFeatures, VhostUserVringAddrFlags,
|
|
||||||
VhostUserVringState,
|
|
||||||
};
|
|
||||||
use vhost::vhost_user::SlaveReqHandler;
|
|
||||||
use vhost::vhost_user::{
|
|
||||||
Error as VhostUserError, Listener, Result as VhostUserResult, SlaveFsCacheReq, SlaveListener,
|
|
||||||
VhostUserSlaveReqHandlerMut,
|
|
||||||
};
|
|
||||||
use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
|
|
||||||
use virtio_queue::Queue;
|
|
||||||
use vm_memory::guest_memory::FileOffset;
|
|
||||||
use vm_memory::GuestAddressSpace;
|
|
||||||
use vm_memory::{bitmap::AtomicBitmap, GuestAddress, GuestMemoryAtomic, MmapRegion};
|
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
|
||||||
|
|
||||||
pub type GuestMemoryMmap = vm_memory::GuestMemoryMmap<AtomicBitmap>;
|
|
||||||
pub type GuestRegionMmap = vm_memory::GuestRegionMmap<AtomicBitmap>;
|
|
||||||
|
|
||||||
const MAX_MEM_SLOTS: u64 = 32;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Errors related to vhost-user daemon.
|
|
||||||
pub enum Error {
|
|
||||||
/// Failed to create a new vhost-user handler.
|
|
||||||
NewVhostUserHandler(VhostUserHandlerError),
|
|
||||||
/// Failed creating vhost-user slave listener.
|
|
||||||
CreateSlaveListener(VhostUserError),
|
|
||||||
/// Failed creating vhost-user slave handler.
|
|
||||||
CreateSlaveReqHandler(VhostUserError),
|
|
||||||
/// Failed starting daemon thread.
|
|
||||||
StartDaemon(io::Error),
|
|
||||||
/// Failed waiting for daemon thread.
|
|
||||||
WaitDaemon(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
|
||||||
/// Failed handling a vhost-user request.
|
|
||||||
HandleRequest(VhostUserError),
|
|
||||||
/// Failed to process queue.
|
|
||||||
ProcessQueue(VringEpollHandlerError),
|
|
||||||
/// Failed to register listener.
|
|
||||||
RegisterListener(io::Error),
|
|
||||||
/// Failed to unregister listener.
|
|
||||||
UnregisterListener(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of vhost-user daemon operations.
|
|
||||||
pub type Result<T> = result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// This trait must be implemented by the caller in order to provide backend
|
|
||||||
/// specific implementation.
|
|
||||||
pub trait VhostUserBackend: Send + Sync + 'static {
|
|
||||||
/// Number of queues.
|
|
||||||
fn num_queues(&self) -> usize;
|
|
||||||
|
|
||||||
/// Depth of each queue.
|
|
||||||
fn max_queue_size(&self) -> usize;
|
|
||||||
|
|
||||||
/// Available virtio features.
|
|
||||||
fn features(&self) -> u64;
|
|
||||||
|
|
||||||
/// Acked virtio features.
|
|
||||||
fn acked_features(&mut self, _features: u64) {}
|
|
||||||
|
|
||||||
/// Virtio protocol features.
|
|
||||||
fn protocol_features(&self) -> VhostUserProtocolFeatures;
|
|
||||||
|
|
||||||
/// Tell the backend if EVENT_IDX has been negotiated.
|
|
||||||
fn set_event_idx(&mut self, enabled: bool);
|
|
||||||
|
|
||||||
/// This function gets called if the backend registered some additional
|
|
||||||
/// listeners onto specific file descriptors. The library can handle
|
|
||||||
/// virtqueues on its own, but does not know what to do with events
|
|
||||||
/// happening on custom listeners.
|
|
||||||
fn handle_event(
|
|
||||||
&self,
|
|
||||||
device_event: u16,
|
|
||||||
evset: epoll::Events,
|
|
||||||
vrings: &[Arc<RwLock<Vring>>],
|
|
||||||
thread_id: usize,
|
|
||||||
) -> result::Result<bool, io::Error>;
|
|
||||||
|
|
||||||
/// Get virtio device configuration.
|
|
||||||
/// A default implementation is provided as we cannot expect all backends
|
|
||||||
/// to implement this function.
|
|
||||||
fn get_config(&self, _offset: u32, _size: u32) -> Vec<u8> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set virtio device configuration.
|
|
||||||
/// A default implementation is provided as we cannot expect all backends
|
|
||||||
/// to implement this function.
|
|
||||||
fn set_config(&mut self, _offset: u32, _buf: &[u8]) -> result::Result<(), io::Error> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provide an exit EventFd
|
|
||||||
/// When this EventFd is written to the worker thread will exit. An optional id may
|
|
||||||
/// also be provided, if it not provided then the exit event will be first event id
|
|
||||||
/// after the last queue
|
|
||||||
fn exit_event(&self, _thread_index: usize) -> Option<(EventFd, Option<u16>)> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set slave fd.
|
|
||||||
/// A default implementation is provided as we cannot expect all backends
|
|
||||||
/// to implement this function.
|
|
||||||
fn set_slave_req_fd(&mut self, _vu_req: SlaveFsCacheReq) {}
|
|
||||||
|
|
||||||
fn queues_per_thread(&self) -> Vec<u64> {
|
|
||||||
vec![0xffff_ffff]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This structure is the public API the backend is allowed to interact with
|
|
||||||
/// in order to run a fully functional vhost-user daemon.
|
|
||||||
pub struct VhostUserDaemon<S: VhostUserBackend> {
|
|
||||||
name: String,
|
|
||||||
handler: Arc<Mutex<VhostUserHandler<S>>>,
|
|
||||||
main_thread: Option<thread::JoinHandle<Result<()>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: VhostUserBackend> VhostUserDaemon<S> {
|
|
||||||
/// Create the daemon instance, providing the backend implementation of
|
|
||||||
/// VhostUserBackend.
|
|
||||||
/// Under the hood, this will start a dedicated thread responsible for
|
|
||||||
/// listening onto registered event. Those events can be vring events or
|
|
||||||
/// custom events from the backend, but they get to be registered later
|
|
||||||
/// during the sequence.
|
|
||||||
pub fn new(name: String, backend: Arc<RwLock<S>>) -> Result<Self> {
|
|
||||||
let handler = Arc::new(Mutex::new(
|
|
||||||
VhostUserHandler::new(backend).map_err(Error::NewVhostUserHandler)?,
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(VhostUserDaemon {
|
|
||||||
name,
|
|
||||||
handler,
|
|
||||||
main_thread: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Listen to the vhost-user socket and run a dedicated thread handling
|
|
||||||
/// all requests coming through this socket. This runs in an infinite loop
|
|
||||||
/// that should be terminating once the other end of the socket (the VMM)
|
|
||||||
/// disconnects.
|
|
||||||
pub fn start_server(&mut self, listener: Listener) -> Result<()> {
|
|
||||||
let mut slave_listener = SlaveListener::new(listener, self.handler.clone())
|
|
||||||
.map_err(Error::CreateSlaveListener)?;
|
|
||||||
let mut slave_handler = slave_listener
|
|
||||||
.accept()
|
|
||||||
.map_err(Error::CreateSlaveReqHandler)?
|
|
||||||
.unwrap();
|
|
||||||
let handle = thread::Builder::new()
|
|
||||||
.name(self.name.clone())
|
|
||||||
.spawn(move || loop {
|
|
||||||
slave_handler
|
|
||||||
.handle_request()
|
|
||||||
.map_err(Error::HandleRequest)?;
|
|
||||||
})
|
|
||||||
.map_err(Error::StartDaemon)?;
|
|
||||||
|
|
||||||
self.main_thread = Some(handle);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Connect to the vhost-user socket and run a dedicated thread handling
|
|
||||||
/// all requests coming through this socket. This runs in an infinite loop
|
|
||||||
/// that should be terminating once the other end of the socket (the VMM)
|
|
||||||
/// hangs up.
|
|
||||||
pub fn start_client(&mut self, socket_path: &str) -> Result<()> {
|
|
||||||
let mut slave_handler = SlaveReqHandler::connect(socket_path, self.handler.clone())
|
|
||||||
.map_err(Error::CreateSlaveReqHandler)?;
|
|
||||||
let handle = thread::Builder::new()
|
|
||||||
.name(self.name.clone())
|
|
||||||
.spawn(move || loop {
|
|
||||||
slave_handler
|
|
||||||
.handle_request()
|
|
||||||
.map_err(Error::HandleRequest)?;
|
|
||||||
})
|
|
||||||
.map_err(Error::StartDaemon)?;
|
|
||||||
|
|
||||||
self.main_thread = Some(handle);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wait for the thread handling the vhost-user socket connection to
|
|
||||||
/// terminate.
|
|
||||||
pub fn wait(&mut self) -> Result<()> {
|
|
||||||
if let Some(handle) = self.main_thread.take() {
|
|
||||||
match handle.join().map_err(Error::WaitDaemon)? {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(Error::HandleRequest(VhostUserError::SocketBroken(_))) => Ok(()),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieve the vring worker. This is necessary to perform further
|
|
||||||
/// actions like registering and unregistering some extra event file
|
|
||||||
/// descriptors.
|
|
||||||
pub fn get_vring_workers(&self) -> Vec<Arc<VringWorker>> {
|
|
||||||
self.handler.lock().unwrap().get_vring_workers()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AddrMapping {
|
|
||||||
vmm_addr: u64,
|
|
||||||
size: u64,
|
|
||||||
gpa_base: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Vring {
|
|
||||||
queue: Queue<GuestMemoryAtomic<GuestMemoryMmap>>,
|
|
||||||
kick: Option<EventFd>,
|
|
||||||
call: Option<EventFd>,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
err: Option<EventFd>,
|
|
||||||
enabled: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vring {
|
|
||||||
fn new(mem: GuestMemoryAtomic<GuestMemoryMmap>, max_queue_size: u16) -> Self {
|
|
||||||
Vring {
|
|
||||||
queue: Queue::new(mem, max_queue_size),
|
|
||||||
kick: None,
|
|
||||||
call: None,
|
|
||||||
err: None,
|
|
||||||
enabled: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mut_queue(&mut self) -> &mut Queue<GuestMemoryAtomic<GuestMemoryMmap>> {
|
|
||||||
&mut self.queue
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn signal_used_queue(&mut self) -> result::Result<(), io::Error> {
|
|
||||||
if let Some(call) = self.call.as_ref() {
|
|
||||||
call.write(1)
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Errors related to vring epoll handler.
|
|
||||||
pub enum VringEpollHandlerError {
|
|
||||||
/// Failed to process the queue from the backend.
|
|
||||||
ProcessQueueBackendProcessing(io::Error),
|
|
||||||
/// Failed to signal used queue.
|
|
||||||
SignalUsedQueue(io::Error),
|
|
||||||
/// Failed to read the event from kick EventFd.
|
|
||||||
HandleEventReadKick(io::Error),
|
|
||||||
/// Failed to handle the event from the backend.
|
|
||||||
HandleEventBackendHandling(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of vring epoll handler operations.
|
|
||||||
type VringEpollHandlerResult<T> = std::result::Result<T, VringEpollHandlerError>;
|
|
||||||
|
|
||||||
struct VringEpollHandler<S: VhostUserBackend> {
|
|
||||||
backend: Arc<RwLock<S>>,
|
|
||||||
vrings: Vec<Arc<RwLock<Vring>>>,
|
|
||||||
exit_event_id: Option<u16>,
|
|
||||||
thread_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: VhostUserBackend> VringEpollHandler<S> {
|
|
||||||
fn handle_event(
|
|
||||||
&self,
|
|
||||||
device_event: u16,
|
|
||||||
evset: epoll::Events,
|
|
||||||
) -> VringEpollHandlerResult<bool> {
|
|
||||||
if self.exit_event_id == Some(device_event) {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let num_queues = self.vrings.len();
|
|
||||||
if (device_event as usize) < num_queues {
|
|
||||||
// If the vring is not enabled, it should not be processed.
|
|
||||||
// But let's not read it (hence lose it) in case it is later enabled.
|
|
||||||
if !self.vrings[device_event as usize].read().unwrap().enabled {
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(kick) = &self.vrings[device_event as usize].read().unwrap().kick {
|
|
||||||
kick.read()
|
|
||||||
.map_err(VringEpollHandlerError::HandleEventReadKick)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.backend
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.handle_event(device_event, evset, &self.vrings, self.thread_id)
|
|
||||||
.map_err(VringEpollHandlerError::HandleEventBackendHandling)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Errors related to vring worker.
|
|
||||||
enum VringWorkerError {
|
|
||||||
/// Failed while waiting for events.
|
|
||||||
EpollWait(io::Error),
|
|
||||||
/// Failed to handle the event.
|
|
||||||
HandleEvent(VringEpollHandlerError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Result of vring worker operations.
|
|
||||||
type VringWorkerResult<T> = std::result::Result<T, VringWorkerError>;
|
|
||||||
|
|
||||||
pub struct VringWorker {
|
|
||||||
epoll_file: File,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for VringWorker {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.epoll_file.as_raw_fd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VringWorker {
|
|
||||||
fn run<S: VhostUserBackend>(&self, handler: VringEpollHandler<S>) -> VringWorkerResult<()> {
|
|
||||||
const EPOLL_EVENTS_LEN: usize = 100;
|
|
||||||
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
|
|
||||||
|
|
||||||
'epoll: loop {
|
|
||||||
let num_events = match epoll::wait(self.epoll_file.as_raw_fd(), -1, &mut events[..]) {
|
|
||||||
Ok(res) => res,
|
|
||||||
Err(e) => {
|
|
||||||
if e.kind() == io::ErrorKind::Interrupted {
|
|
||||||
// It's well defined from the epoll_wait() syscall
|
|
||||||
// documentation that the epoll loop can be interrupted
|
|
||||||
// before any of the requested events occurred or the
|
|
||||||
// timeout expired. In both those cases, epoll_wait()
|
|
||||||
// returns an error of type EINTR, but this should not
|
|
||||||
// be considered as a regular error. Instead it is more
|
|
||||||
// appropriate to retry, by calling into epoll_wait().
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return Err(VringWorkerError::EpollWait(e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for event in events.iter().take(num_events) {
|
|
||||||
let evset = match epoll::Events::from_bits(event.events) {
|
|
||||||
Some(evset) => evset,
|
|
||||||
None => {
|
|
||||||
let evbits = event.events;
|
|
||||||
println!("epoll: ignoring unknown event set: 0x{:x}", evbits);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let ev_type = event.data as u16;
|
|
||||||
|
|
||||||
if handler
|
|
||||||
.handle_event(ev_type, evset)
|
|
||||||
.map_err(VringWorkerError::HandleEvent)?
|
|
||||||
{
|
|
||||||
break 'epoll;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a custom event only meaningful to the caller. When this event
|
|
||||||
/// is later triggered, and because only the caller knows what to do about
|
|
||||||
/// it, the backend implementation of `handle_event` will be called.
|
|
||||||
/// This lets entire control to the caller about what needs to be done for
|
|
||||||
/// this special event, without forcing it to run its own dedicated epoll
|
|
||||||
/// loop for it.
|
|
||||||
pub fn register_listener(
|
|
||||||
&self,
|
|
||||||
fd: RawFd,
|
|
||||||
ev_type: epoll::Events,
|
|
||||||
data: u64,
|
|
||||||
) -> result::Result<(), io::Error> {
|
|
||||||
epoll::ctl(
|
|
||||||
self.epoll_file.as_raw_fd(),
|
|
||||||
epoll::ControlOptions::EPOLL_CTL_ADD,
|
|
||||||
fd,
|
|
||||||
epoll::Event::new(ev_type, data),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unregister a custom event. If the custom event is triggered after this
|
|
||||||
/// function has been called, nothing will happen as it will be removed
|
|
||||||
/// from the list of file descriptors the epoll loop is listening to.
|
|
||||||
pub fn unregister_listener(
|
|
||||||
&self,
|
|
||||||
fd: RawFd,
|
|
||||||
ev_type: epoll::Events,
|
|
||||||
data: u64,
|
|
||||||
) -> result::Result<(), io::Error> {
|
|
||||||
epoll::ctl(
|
|
||||||
self.epoll_file.as_raw_fd(),
|
|
||||||
epoll::ControlOptions::EPOLL_CTL_DEL,
|
|
||||||
fd,
|
|
||||||
epoll::Event::new(ev_type, data),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
/// Errors related to vhost-user handler.
|
|
||||||
pub enum VhostUserHandlerError {
|
|
||||||
/// Failed to create epoll file descriptor.
|
|
||||||
EpollCreateFd(io::Error),
|
|
||||||
/// Failed to spawn vring worker.
|
|
||||||
SpawnVringWorker(io::Error),
|
|
||||||
/// Could not find the mapping from memory regions.
|
|
||||||
MissingMemoryMapping,
|
|
||||||
/// Could not register exit event
|
|
||||||
RegisterExitEvent(io::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Display for VhostUserHandlerError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
VhostUserHandlerError::EpollCreateFd(e) => write!(f, "failed creating epoll fd: {}", e),
|
|
||||||
VhostUserHandlerError::SpawnVringWorker(e) => {
|
|
||||||
write!(f, "failed spawning the vring worker: {}", e)
|
|
||||||
}
|
|
||||||
VhostUserHandlerError::MissingMemoryMapping => write!(f, "Missing memory mapping"),
|
|
||||||
VhostUserHandlerError::RegisterExitEvent(e) => {
|
|
||||||
write!(f, "Failed to register exit event: {}", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for VhostUserHandlerError {}
|
|
||||||
|
|
||||||
/// Result of vhost-user handler operations.
|
|
||||||
type VhostUserHandlerResult<T> = std::result::Result<T, VhostUserHandlerError>;
|
|
||||||
|
|
||||||
struct VhostUserHandler<S: VhostUserBackend> {
|
|
||||||
backend: Arc<RwLock<S>>,
|
|
||||||
workers: Vec<Arc<VringWorker>>,
|
|
||||||
owned: bool,
|
|
||||||
acked_features: u64,
|
|
||||||
num_queues: usize,
|
|
||||||
max_queue_size: usize,
|
|
||||||
queues_per_thread: Vec<u64>,
|
|
||||||
mappings: Vec<AddrMapping>,
|
|
||||||
guest_memory: GuestMemoryAtomic<GuestMemoryMmap>,
|
|
||||||
vrings: Vec<Arc<RwLock<Vring>>>,
|
|
||||||
worker_threads: Vec<thread::JoinHandle<VringWorkerResult<()>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: VhostUserBackend> VhostUserHandler<S> {
|
|
||||||
fn new(backend: Arc<RwLock<S>>) -> VhostUserHandlerResult<Self> {
|
|
||||||
let num_queues = backend.read().unwrap().num_queues();
|
|
||||||
let max_queue_size = backend.read().unwrap().max_queue_size();
|
|
||||||
let queues_per_thread = backend.read().unwrap().queues_per_thread();
|
|
||||||
let guest_memory = GuestMemoryAtomic::new(GuestMemoryMmap::new());
|
|
||||||
|
|
||||||
let mut vrings: Vec<Arc<RwLock<Vring>>> = Vec::new();
|
|
||||||
for _ in 0..num_queues {
|
|
||||||
let vring = Arc::new(RwLock::new(Vring::new(
|
|
||||||
guest_memory.clone(),
|
|
||||||
max_queue_size as u16,
|
|
||||||
)));
|
|
||||||
vrings.push(vring);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut workers = Vec::new();
|
|
||||||
let mut worker_threads = Vec::new();
|
|
||||||
for (thread_id, queues_mask) in queues_per_thread.iter().enumerate() {
|
|
||||||
// Create the epoll file descriptor
|
|
||||||
let epoll_fd = epoll::create(true).map_err(VhostUserHandlerError::EpollCreateFd)?;
|
|
||||||
// Use 'File' to enforce closing on 'epoll_fd'
|
|
||||||
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
|
|
||||||
|
|
||||||
let vring_worker = Arc::new(VringWorker { epoll_file });
|
|
||||||
let worker = vring_worker.clone();
|
|
||||||
|
|
||||||
let exit_event_id = if let Some((exit_event_fd, exit_event_id)) =
|
|
||||||
backend.read().unwrap().exit_event(thread_id)
|
|
||||||
{
|
|
||||||
let exit_event_id = exit_event_id.unwrap_or(num_queues as u16);
|
|
||||||
worker
|
|
||||||
.register_listener(
|
|
||||||
exit_event_fd.as_raw_fd(),
|
|
||||||
epoll::Events::EPOLLIN,
|
|
||||||
u64::from(exit_event_id),
|
|
||||||
)
|
|
||||||
.map_err(VhostUserHandlerError::RegisterExitEvent)?;
|
|
||||||
Some(exit_event_id)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut thread_vrings: Vec<Arc<RwLock<Vring>>> = Vec::new();
|
|
||||||
for (index, vring) in vrings.iter().enumerate() {
|
|
||||||
if (queues_mask >> index) & 1u64 == 1u64 {
|
|
||||||
thread_vrings.push(vring.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let vring_handler = VringEpollHandler {
|
|
||||||
backend: backend.clone(),
|
|
||||||
vrings: thread_vrings,
|
|
||||||
exit_event_id,
|
|
||||||
thread_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
let worker_thread = thread::Builder::new()
|
|
||||||
.name("vring_worker".to_string())
|
|
||||||
.spawn(move || vring_worker.run(vring_handler))
|
|
||||||
.map_err(VhostUserHandlerError::SpawnVringWorker)?;
|
|
||||||
|
|
||||||
workers.push(worker);
|
|
||||||
worker_threads.push(worker_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(VhostUserHandler {
|
|
||||||
backend,
|
|
||||||
workers,
|
|
||||||
owned: false,
|
|
||||||
acked_features: 0,
|
|
||||||
num_queues,
|
|
||||||
max_queue_size,
|
|
||||||
queues_per_thread,
|
|
||||||
mappings: Vec::new(),
|
|
||||||
guest_memory,
|
|
||||||
vrings,
|
|
||||||
worker_threads,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_vring_workers(&self) -> Vec<Arc<VringWorker>> {
|
|
||||||
self.workers.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vmm_va_to_gpa(&self, vmm_va: u64) -> VhostUserHandlerResult<u64> {
|
|
||||||
for mapping in self.mappings.iter() {
|
|
||||||
if vmm_va >= mapping.vmm_addr && vmm_va < mapping.vmm_addr + mapping.size {
|
|
||||||
return Ok(vmm_va - mapping.vmm_addr + mapping.gpa_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(VhostUserHandlerError::MissingMemoryMapping)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: VhostUserBackend> VhostUserSlaveReqHandlerMut for VhostUserHandler<S> {
|
|
||||||
fn set_owner(&mut self) -> VhostUserResult<()> {
|
|
||||||
if self.owned {
|
|
||||||
return Err(VhostUserError::InvalidOperation);
|
|
||||||
}
|
|
||||||
self.owned = true;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset_owner(&mut self) -> VhostUserResult<()> {
|
|
||||||
self.owned = false;
|
|
||||||
self.acked_features = 0;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_features(&mut self) -> VhostUserResult<u64> {
|
|
||||||
Ok(self.backend.read().unwrap().features())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_features(&mut self, features: u64) -> VhostUserResult<()> {
|
|
||||||
if (features & !self.backend.read().unwrap().features()) != 0 {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.acked_features = features;
|
|
||||||
|
|
||||||
// If VHOST_USER_F_PROTOCOL_FEATURES has not been negotiated,
|
|
||||||
// the ring is initialized in an enabled state.
|
|
||||||
// If VHOST_USER_F_PROTOCOL_FEATURES has been negotiated,
|
|
||||||
// the ring is initialized in a disabled state. Client must not
|
|
||||||
// pass data to/from the backend until ring is enabled by
|
|
||||||
// VHOST_USER_SET_VRING_ENABLE with parameter 1, or after it has
|
|
||||||
// been disabled by VHOST_USER_SET_VRING_ENABLE with parameter 0.
|
|
||||||
let vring_enabled =
|
|
||||||
self.acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() == 0;
|
|
||||||
for vring in self.vrings.iter_mut() {
|
|
||||||
vring.write().unwrap().enabled = vring_enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.backend
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.acked_features(self.acked_features);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_protocol_features(&mut self) -> VhostUserResult<VhostUserProtocolFeatures> {
|
|
||||||
Ok(self.backend.read().unwrap().protocol_features())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_protocol_features(&mut self, _features: u64) -> VhostUserResult<()> {
|
|
||||||
// Note: slave that reported VHOST_USER_F_PROTOCOL_FEATURES must
|
|
||||||
// support this message even before VHOST_USER_SET_FEATURES was
|
|
||||||
// called.
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_mem_table(
|
|
||||||
&mut self,
|
|
||||||
ctx: &[VhostUserMemoryRegion],
|
|
||||||
mut files: Vec<File>,
|
|
||||||
) -> VhostUserResult<()> {
|
|
||||||
// We need to create tuple of ranges from the list of VhostUserMemoryRegion
|
|
||||||
// that we get from the caller.
|
|
||||||
let mut regions: Vec<(GuestAddress, usize, Option<FileOffset>)> = Vec::new();
|
|
||||||
let mut mappings: Vec<AddrMapping> = Vec::new();
|
|
||||||
|
|
||||||
for region in ctx.iter() {
|
|
||||||
let g_addr = GuestAddress(region.guest_phys_addr);
|
|
||||||
let len = region.memory_size as usize;
|
|
||||||
let f_off = FileOffset::new(files.remove(0), region.mmap_offset);
|
|
||||||
|
|
||||||
regions.push((g_addr, len, Some(f_off)));
|
|
||||||
mappings.push(AddrMapping {
|
|
||||||
vmm_addr: region.user_addr,
|
|
||||||
size: region.memory_size,
|
|
||||||
gpa_base: region.guest_phys_addr,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let mem = GuestMemoryMmap::from_ranges_with_files(regions).map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
self.guest_memory.lock().unwrap().replace(mem);
|
|
||||||
self.mappings = mappings;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_queue_num(&mut self) -> VhostUserResult<u64> {
|
|
||||||
Ok(self.num_queues as u64)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_num(&mut self, index: u32, num: u32) -> VhostUserResult<()> {
|
|
||||||
if index as usize >= self.num_queues || num == 0 || num as usize > self.max_queue_size {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.size = num as u16;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_addr(
|
|
||||||
&mut self,
|
|
||||||
index: u32,
|
|
||||||
_flags: VhostUserVringAddrFlags,
|
|
||||||
descriptor: u64,
|
|
||||||
used: u64,
|
|
||||||
available: u64,
|
|
||||||
_log: u64,
|
|
||||||
) -> VhostUserResult<()> {
|
|
||||||
if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.mappings.is_empty() {
|
|
||||||
let desc_table = self.vmm_va_to_gpa(descriptor).map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
let avail_ring = self.vmm_va_to_gpa(available).map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
let used_ring = self.vmm_va_to_gpa(used).map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.desc_table = GuestAddress(desc_table);
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.avail_ring = GuestAddress(avail_ring);
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.used_ring = GuestAddress(used_ring);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(VhostUserError::InvalidParam)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_base(&mut self, index: u32, base: u32) -> VhostUserResult<()> {
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.set_next_avail(base as u16);
|
|
||||||
|
|
||||||
let event_idx: bool = (self.acked_features & (1 << VIRTIO_RING_F_EVENT_IDX)) != 0;
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.mut_queue()
|
|
||||||
.set_event_idx(event_idx);
|
|
||||||
self.backend.write().unwrap().set_event_idx(event_idx);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_vring_base(&mut self, index: u32) -> VhostUserResult<VhostUserVringState> {
|
|
||||||
if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
// Quote from vhost-user specification:
|
|
||||||
// Client must start ring upon receiving a kick (that is, detecting
|
|
||||||
// that file descriptor is readable) on the descriptor specified by
|
|
||||||
// VHOST_USER_SET_VRING_KICK, and stop ring upon receiving
|
|
||||||
// VHOST_USER_GET_VRING_BASE.
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.ready = false;
|
|
||||||
if let Some(fd) = self.vrings[index as usize].read().unwrap().kick.as_ref() {
|
|
||||||
for (thread_index, queues_mask) in self.queues_per_thread.iter().enumerate() {
|
|
||||||
let shifted_queues_mask = queues_mask >> index;
|
|
||||||
if shifted_queues_mask & 1u64 == 1u64 {
|
|
||||||
let evt_idx = queues_mask.count_ones() - shifted_queues_mask.count_ones();
|
|
||||||
self.workers[thread_index]
|
|
||||||
.unregister_listener(
|
|
||||||
fd.as_raw_fd(),
|
|
||||||
epoll::Events::EPOLLIN,
|
|
||||||
u64::from(evt_idx),
|
|
||||||
)
|
|
||||||
.map_err(VhostUserError::ReqHandlerError)?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let next_avail = self.vrings[index as usize]
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.next_avail();
|
|
||||||
|
|
||||||
Ok(VhostUserVringState::new(index, u32::from(next_avail)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_kick(&mut self, index: u8, fd: Option<File>) -> VhostUserResult<()> {
|
|
||||||
if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vrings[index as usize].write().unwrap().kick =
|
|
||||||
fd.map(|x| unsafe { EventFd::from_raw_fd(x.into_raw_fd()) });
|
|
||||||
|
|
||||||
// Quote from vhost-user specification:
|
|
||||||
// Client must start ring upon receiving a kick (that is, detecting
|
|
||||||
// that file descriptor is readable) on the descriptor specified by
|
|
||||||
// VHOST_USER_SET_VRING_KICK, and stop ring upon receiving
|
|
||||||
// VHOST_USER_GET_VRING_BASE.
|
|
||||||
self.vrings[index as usize]
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.queue
|
|
||||||
.state
|
|
||||||
.ready = true;
|
|
||||||
if let Some(fd) = self.vrings[index as usize].read().unwrap().kick.as_ref() {
|
|
||||||
for (thread_index, queues_mask) in self.queues_per_thread.iter().enumerate() {
|
|
||||||
let shifted_queues_mask = queues_mask >> index;
|
|
||||||
if shifted_queues_mask & 1u64 == 1u64 {
|
|
||||||
let evt_idx = queues_mask.count_ones() - shifted_queues_mask.count_ones();
|
|
||||||
self.workers[thread_index]
|
|
||||||
.register_listener(
|
|
||||||
fd.as_raw_fd(),
|
|
||||||
epoll::Events::EPOLLIN,
|
|
||||||
u64::from(evt_idx),
|
|
||||||
)
|
|
||||||
.map_err(VhostUserError::ReqHandlerError)?;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_call(&mut self, index: u8, fd: Option<File>) -> VhostUserResult<()> {
|
|
||||||
if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vrings[index as usize].write().unwrap().call =
|
|
||||||
fd.map(|x| unsafe { EventFd::from_raw_fd(x.into_raw_fd()) });
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_err(&mut self, index: u8, fd: Option<File>) -> VhostUserResult<()> {
|
|
||||||
if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vrings[index as usize].write().unwrap().err =
|
|
||||||
fd.map(|x| unsafe { EventFd::from_raw_fd(x.into_raw_fd()) });
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_vring_enable(&mut self, index: u32, enable: bool) -> VhostUserResult<()> {
|
|
||||||
// This request should be handled only when VHOST_USER_F_PROTOCOL_FEATURES
|
|
||||||
// has been negotiated.
|
|
||||||
if self.acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits() == 0 {
|
|
||||||
return Err(VhostUserError::InvalidOperation);
|
|
||||||
} else if index as usize >= self.num_queues {
|
|
||||||
return Err(VhostUserError::InvalidParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slave must not pass data to/from the backend until ring is
|
|
||||||
// enabled by VHOST_USER_SET_VRING_ENABLE with parameter 1,
|
|
||||||
// or after it has been disabled by VHOST_USER_SET_VRING_ENABLE
|
|
||||||
// with parameter 0.
|
|
||||||
self.vrings[index as usize].write().unwrap().enabled = enable;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_config(
|
|
||||||
&mut self,
|
|
||||||
offset: u32,
|
|
||||||
size: u32,
|
|
||||||
_flags: VhostUserConfigFlags,
|
|
||||||
) -> VhostUserResult<Vec<u8>> {
|
|
||||||
Ok(self.backend.read().unwrap().get_config(offset, size))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_config(
|
|
||||||
&mut self,
|
|
||||||
offset: u32,
|
|
||||||
buf: &[u8],
|
|
||||||
_flags: VhostUserConfigFlags,
|
|
||||||
) -> VhostUserResult<()> {
|
|
||||||
self.backend
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.set_config(offset, buf)
|
|
||||||
.map_err(VhostUserError::ReqHandlerError)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_slave_req_fd(&mut self, vu_req: SlaveFsCacheReq) {
|
|
||||||
self.backend.write().unwrap().set_slave_req_fd(vu_req);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_max_mem_slots(&mut self) -> VhostUserResult<u64> {
|
|
||||||
Ok(MAX_MEM_SLOTS)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_mem_region(
|
|
||||||
&mut self,
|
|
||||||
region: &VhostUserSingleMemoryRegion,
|
|
||||||
fd: File,
|
|
||||||
) -> VhostUserResult<()> {
|
|
||||||
let mmap_region = MmapRegion::from_file(
|
|
||||||
FileOffset::new(fd, region.mmap_offset),
|
|
||||||
region.memory_size as usize,
|
|
||||||
)
|
|
||||||
.map_err(|e| VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)))?;
|
|
||||||
let guest_region = Arc::new(
|
|
||||||
GuestRegionMmap::new(mmap_region, GuestAddress(region.guest_phys_addr)).map_err(
|
|
||||||
|e| VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e)),
|
|
||||||
)?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let guest_memory = self
|
|
||||||
.guest_memory
|
|
||||||
.memory()
|
|
||||||
.insert_region(guest_region)
|
|
||||||
.map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
self.guest_memory.lock().unwrap().replace(guest_memory);
|
|
||||||
|
|
||||||
self.mappings.push(AddrMapping {
|
|
||||||
vmm_addr: region.user_addr,
|
|
||||||
size: region.memory_size,
|
|
||||||
gpa_base: region.guest_phys_addr,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_mem_region(&mut self, region: &VhostUserSingleMemoryRegion) -> VhostUserResult<()> {
|
|
||||||
let (guest_memory, _) = self
|
|
||||||
.guest_memory
|
|
||||||
.memory()
|
|
||||||
.remove_region(GuestAddress(region.guest_phys_addr), region.memory_size)
|
|
||||||
.map_err(|e| {
|
|
||||||
VhostUserError::ReqHandlerError(io::Error::new(io::ErrorKind::Other, e))
|
|
||||||
})?;
|
|
||||||
self.guest_memory.lock().unwrap().replace(guest_memory);
|
|
||||||
|
|
||||||
self.mappings
|
|
||||||
.retain(|mapping| mapping.gpa_base != region.guest_phys_addr);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_inflight_fd(
|
|
||||||
&mut self,
|
|
||||||
_: &VhostUserInflight,
|
|
||||||
) -> VhostUserResult<(VhostUserInflight, File)> {
|
|
||||||
std::unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_inflight_fd(&mut self, _: &VhostUserInflight, _: File) -> VhostUserResult<()> {
|
|
||||||
std::unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: VhostUserBackend> Drop for VhostUserHandler<S> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
for thread in self.worker_threads.drain(..) {
|
|
||||||
if let Err(e) = thread.join() {
|
|
||||||
error!("Error in vring worker: {:?}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user