mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-06-26 15:32:30 +00:00
runtime-rs: Add basic CH implementation
Add a basic runtime-rs `Hypervisor` trait implementation for Cloud Hypervisor (CH). > **Notes:** > > - This only supports a default Kata configuration for CH currently. > > - Since this feature is still under development, `cargo` features have > been added to enable the feature optionally. The default is to not enable > currently since the code is not ready for general use. > > To enable the feature for testing and development, enable the > `cloud-hypervisor` feature in the `virt_container` crate and enable the > `cloud-hypervisor` feature for its `hypervisor` dependency. Fixes: #5242. Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
This commit is contained in:
parent
545151829d
commit
37b594c0d2
196
src/runtime-rs/Cargo.lock
generated
196
src/runtime-rs/Cargo.lock
generated
@ -81,9 +81,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.57"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc"
|
||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
||||
|
||||
[[package]]
|
||||
name = "api_client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/cloud-hypervisor/cloud-hypervisor?tag=v27.0#2ba6a9bfcfd79629aecf77504fa554ab821d138e"
|
||||
dependencies = [
|
||||
"vmm-sys-util 0.10.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
@ -412,6 +420,17 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ch-config"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"api_client",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.22"
|
||||
@ -934,9 +953,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e"
|
||||
checksum = "13e2792b0ff0340399d58445b88fd9770e3489eff258a4cbc1523418f12abf84"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -949,9 +968,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
checksum = "2e5317663a9089767a1ec00a487df42e0ca174b61b4483213ac24448e4664df5"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
@ -959,15 +978,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
checksum = "ec90ff4d0fe1f57d600049061dc6bb68ed03c7d2fbd697274c41805dcb3f8608"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
checksum = "e8de0a35a6ab97ec8869e32a2473f4b1324459e14c29275d14b10cb1fd19b50e"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
@ -976,9 +995,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b"
|
||||
checksum = "bfb8371b6fb2aeb2d280374607aeabfc99d95c72edfe51692e42d3d7f0d08531"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
@ -997,9 +1016,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512"
|
||||
checksum = "95a73af87da33b5acf53acfebdc339fe592ecf5357ac7c0a7734ab9d8c876a70"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -1008,15 +1027,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868"
|
||||
checksum = "f310820bb3e8cfd46c80db4d7fb8353e15dfff853a127158425f31e0be6c8364"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a"
|
||||
checksum = "dcf79a1bf610b10f42aea489289c5a2c478a786509693b80cd39c44ccd936366"
|
||||
|
||||
[[package]]
|
||||
name = "futures-timer"
|
||||
@ -1026,9 +1045,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.21"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
checksum = "9c1d6de3acfef38d2be4b1f543f553131788603495be83da675e180c8d6b7bd1"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -1114,7 +1133,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7df0ee4b237afb71e99f7e2fbd840ffec2d6c4bb569f69b2af18aa1f63077d38"
|
||||
dependencies = [
|
||||
"dashmap",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"futures-timer",
|
||||
"no-std-compat",
|
||||
"nonzero_ext",
|
||||
@ -1236,8 +1255,10 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"ch-config",
|
||||
"dbs-utils",
|
||||
"dragonball",
|
||||
"futures 0.3.26",
|
||||
"go-flag",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
@ -1246,6 +1267,7 @@ dependencies = [
|
||||
"nix 0.24.2",
|
||||
"persist",
|
||||
"rand 0.8.5",
|
||||
"safe-path 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"seccompiler",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@ -1551,14 +1573,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.3"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713d550d9b44d89174e066b7a6217ae06234c10cb47819a88290d2b353c31799"
|
||||
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1612,7 +1634,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65b4b14489ab424703c092062176d52ba55485a89c076b4f9db05092b7223aa6"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"log",
|
||||
"netlink-packet-core",
|
||||
"netlink-sys",
|
||||
@ -1627,7 +1649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92b654097027250401127914afb37cb1f311df6610a9891ff07a757e94199027"
|
||||
dependencies = [
|
||||
"bytes 1.1.0",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"libc",
|
||||
"log",
|
||||
"tokio",
|
||||
@ -1783,7 +1805,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"blake3",
|
||||
"fuse-backend-rs",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@ -1811,7 +1833,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"dbs-uhttp",
|
||||
"fuse-backend-rs",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"governor",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
@ -1931,7 +1953,7 @@ dependencies = [
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
"windows-sys 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1955,7 +1977,7 @@ dependencies = [
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
"libc",
|
||||
"safe-path",
|
||||
"safe-path 0.1.0",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shim-interface",
|
||||
@ -2025,9 +2047,9 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.39"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f"
|
||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -2321,7 +2343,7 @@ dependencies = [
|
||||
"bitflags",
|
||||
"byte-unit 4.0.17",
|
||||
"cgroups-rs",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"hypervisor",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
@ -2361,7 +2383,7 @@ version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46f1cfa18f8cebe685373a2697915d7e0db3b4554918bba118385e0f71f258a7"
|
||||
dependencies = [
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"log",
|
||||
"netlink-packet-route",
|
||||
"netlink-proto",
|
||||
@ -2432,6 +2454,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "safe-path"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "980abdd3220aa19b67ca3ea07b173ca36383f18ae48cde696d90c8af39447ffb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scoped-tls"
|
||||
version = "1.0.0"
|
||||
@ -2455,18 +2486,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.143"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553"
|
||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.143"
|
||||
version = "1.0.152"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391"
|
||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2475,9 +2506,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.83"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
|
||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
@ -2729,9 +2760,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.96"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf"
|
||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -2857,22 +2888,22 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.19.1"
|
||||
version = "1.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95eec79ea28c00a365f539f1961e9278fbcaf81c0ff6aaf0e93c181352446948"
|
||||
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes 1.1.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.1",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"winapi",
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2907,7 +2938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e0723fc001950a3b018947b05eeb45014fd2b7c6e8f292502193ab74486bdb6"
|
||||
dependencies = [
|
||||
"bytes 0.4.12",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"libc",
|
||||
"tokio",
|
||||
"vsock",
|
||||
@ -2971,7 +3002,7 @@ checksum = "2ecfff459a859c6ba6668ff72b34c2f1d94d9d58f7088414c2674ad0f31cc7d8"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"byteorder",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"libc",
|
||||
"log",
|
||||
"nix 0.23.1",
|
||||
@ -3105,7 +3136,7 @@ dependencies = [
|
||||
"awaitgroup",
|
||||
"common",
|
||||
"containerd-shim-protos",
|
||||
"futures 0.3.21",
|
||||
"futures 0.3.26",
|
||||
"hypervisor",
|
||||
"kata-sys-util",
|
||||
"kata-types",
|
||||
@ -3366,43 +3397,100 @@ version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||
dependencies = [
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_msvc",
|
||||
"windows_aarch64_msvc 0.36.1",
|
||||
"windows_i686_gnu 0.36.1",
|
||||
"windows_i686_msvc 0.36.1",
|
||||
"windows_x86_64_gnu 0.36.1",
|
||||
"windows_x86_64_msvc 0.36.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc 0.42.1",
|
||||
"windows_i686_gnu 0.42.1",
|
||||
"windows_i686_msvc 0.42.1",
|
||||
"windows_x86_64_gnu 0.42.1",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc 0.42.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.11.2+zstd.1.5.2"
|
||||
|
@ -32,4 +32,14 @@ shim-interface = { path = "../../../libs/shim-interface" }
|
||||
|
||||
dragonball = { path = "../../../dragonball", features = ["atomic-guest-memory", "virtio-vsock", "hotplug", "virtio-blk", "virtio-net", "virtio-fs","dbs-upcall"] }
|
||||
|
||||
ch-config = { path = "ch-config", optional = true }
|
||||
|
||||
futures = "0.3.25"
|
||||
safe-path = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# Feature is not yet complete, so not enabled by default.
|
||||
# See https://github.com/kata-containers/kata-containers/issues/6264.
|
||||
cloud-hypervisor = ["ch-config"]
|
||||
|
22
src/runtime-rs/crates/hypervisor/ch-config/Cargo.toml
Normal file
22
src/runtime-rs/crates/hypervisor/ch-config/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
# Copyright (c) 2022-2023 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
[package]
|
||||
name = "ch-config"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.68"
|
||||
serde = { version = "1.0.145", features = ["rc", "derive"] }
|
||||
serde_json = "1.0.91"
|
||||
tokio = { version = "1.25.0", features = ["sync", "rt"] }
|
||||
|
||||
# Cloud Hypervisor public HTTP API functions
|
||||
# Note that the version specified is not necessarily the version of CH
|
||||
# being used. This version is used to pin the CH config structure
|
||||
# which is relatively static.
|
||||
api_client = { git = "https://github.com/cloud-hypervisor/cloud-hypervisor", crate = "api_client", tag = "v27.0" }
|
274
src/runtime-rs/crates/hypervisor/ch-config/src/ch_api.rs
Normal file
274
src/runtime-rs/crates/hypervisor/ch-config/src/ch_api.rs
Normal file
@ -0,0 +1,274 @@
|
||||
// Copyright (c) 2022-2023 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::net_util::MAC_ADDR_LEN;
|
||||
use crate::{
|
||||
ConsoleConfig, ConsoleOutputMode, CpuTopology, CpusConfig, DeviceConfig, FsConfig, MacAddr,
|
||||
MemoryConfig, NetConfig, PayloadConfig, PmemConfig, RngConfig, VmConfig, VsockConfig,
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use api_client::simple_api_full_command_and_response;
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::path::PathBuf;
|
||||
use tokio::task;
|
||||
|
||||
pub async fn cloud_hypervisor_vmm_ping(mut socket: UnixStream) -> Result<Option<String>> {
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response = simple_api_full_command_and_response(&mut socket, "GET", "vmm.ping", None)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
pub async fn cloud_hypervisor_vmm_shutdown(mut socket: UnixStream) -> Result<Option<String>> {
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response =
|
||||
simple_api_full_command_and_response(&mut socket, "PUT", "vmm.shutdown", None)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
pub async fn cloud_hypervisor_vm_create(
|
||||
sandbox_path: String,
|
||||
vsock_socket_path: String,
|
||||
mut socket: UnixStream,
|
||||
shared_fs_devices: Option<Vec<FsConfig>>,
|
||||
pmem_devices: Option<Vec<PmemConfig>>,
|
||||
) -> Result<Option<String>> {
|
||||
let cfg = cloud_hypervisor_vm_create_cfg(
|
||||
sandbox_path,
|
||||
vsock_socket_path,
|
||||
shared_fs_devices,
|
||||
pmem_devices,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let serialised = serde_json::to_string_pretty(&cfg)?;
|
||||
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let data = Some(serialised.as_str());
|
||||
|
||||
let response = simple_api_full_command_and_response(&mut socket, "PUT", "vm.create", data)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
pub async fn cloud_hypervisor_vm_start(mut socket: UnixStream) -> Result<Option<String>> {
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response = simple_api_full_command_and_response(&mut socket, "PUT", "vm.boot", None)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn cloud_hypervisor_vm_stop(mut socket: UnixStream) -> Result<Option<String>> {
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response =
|
||||
simple_api_full_command_and_response(&mut socket, "PUT", "vm.shutdown", None)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn cloud_hypervisor_vm_device_add(mut socket: UnixStream) -> Result<Option<String>> {
|
||||
let device_config = DeviceConfig::default();
|
||||
|
||||
task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response = simple_api_full_command_and_response(
|
||||
&mut socket,
|
||||
"PUT",
|
||||
"vm.add-device",
|
||||
Some(&serde_json::to_string(&device_config)?),
|
||||
)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
pub async fn cloud_hypervisor_vm_fs_add(
|
||||
mut socket: UnixStream,
|
||||
fs_config: FsConfig,
|
||||
) -> Result<Option<String>> {
|
||||
let result = task::spawn_blocking(move || -> Result<Option<String>> {
|
||||
let response = simple_api_full_command_and_response(
|
||||
&mut socket,
|
||||
"PUT",
|
||||
"vm.add-fs",
|
||||
Some(&serde_json::to_string(&fs_config)?),
|
||||
)
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
Ok(response)
|
||||
})
|
||||
.await?;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
pub async fn cloud_hypervisor_vm_create_cfg(
|
||||
// FIXME:
|
||||
_sandbox_path: String,
|
||||
vsock_socket_path: String,
|
||||
shared_fs_devices: Option<Vec<FsConfig>>,
|
||||
pmem_devices: Option<Vec<PmemConfig>>,
|
||||
) -> Result<VmConfig> {
|
||||
let topology = CpuTopology {
|
||||
threads_per_core: 1,
|
||||
cores_per_die: 12,
|
||||
dies_per_package: 1,
|
||||
packages: 1,
|
||||
};
|
||||
|
||||
let cpus = CpusConfig {
|
||||
boot_vcpus: 1,
|
||||
max_vcpus: 12,
|
||||
max_phys_bits: 46,
|
||||
topology: Some(topology),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let rng = RngConfig {
|
||||
src: PathBuf::from("/dev/urandom"),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let kernel_args = vec![
|
||||
"root=/dev/pmem0p1",
|
||||
"rootflags=dax,data=ordered,errors=remount-ro",
|
||||
"ro",
|
||||
"rootfstype=ext4",
|
||||
"panic=1",
|
||||
"no_timer_check",
|
||||
"noreplace-smp",
|
||||
"console=ttyS0,115200n8",
|
||||
"systemd.log_target=console",
|
||||
"systemd.unit=kata-containers",
|
||||
"systemd.mask=systemd-networkd.service",
|
||||
"systemd.mask=systemd-networkd.socket",
|
||||
"agent.log=debug",
|
||||
];
|
||||
|
||||
let cmdline = kernel_args.join(" ");
|
||||
|
||||
let kernel = PathBuf::from("/opt/kata/share/kata-containers/vmlinux.container");
|
||||
|
||||
// Note that PmemConfig replaces the PayloadConfig.initrd.
|
||||
let payload = PayloadConfig {
|
||||
kernel: Some(kernel),
|
||||
cmdline: Some(cmdline),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let serial = ConsoleConfig {
|
||||
mode: ConsoleOutputMode::Tty,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let ip = Ipv4Addr::new(192, 168, 10, 10);
|
||||
let mask = Ipv4Addr::new(255, 255, 255, 0);
|
||||
|
||||
let mac_str = "12:34:56:78:90:01";
|
||||
|
||||
let mac = parse_mac(mac_str)?;
|
||||
|
||||
let network = NetConfig {
|
||||
ip,
|
||||
mask,
|
||||
mac,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let memory = MemoryConfig {
|
||||
size: (1024 * 1024 * 2048),
|
||||
|
||||
// Required
|
||||
shared: true,
|
||||
|
||||
prefault: false,
|
||||
hugepages: false,
|
||||
mergeable: false,
|
||||
|
||||
// FIXME:
|
||||
hotplug_size: Some(16475226112),
|
||||
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let fs = shared_fs_devices;
|
||||
let pmem = pmem_devices;
|
||||
|
||||
let vsock = VsockConfig {
|
||||
cid: 3,
|
||||
socket: PathBuf::from(vsock_socket_path),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cfg = VmConfig {
|
||||
cpus,
|
||||
memory,
|
||||
fs,
|
||||
serial,
|
||||
pmem,
|
||||
payload: Some(payload),
|
||||
vsock: Some(vsock),
|
||||
rng,
|
||||
net: Some(vec![network]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(cfg)
|
||||
}
|
||||
|
||||
fn parse_mac<S>(s: &S) -> Result<MacAddr>
|
||||
where
|
||||
S: AsRef<str> + ?Sized + Display,
|
||||
{
|
||||
let v: Vec<&str> = s.as_ref().split(':').collect();
|
||||
let mut bytes = [0u8; MAC_ADDR_LEN];
|
||||
|
||||
if v.len() != MAC_ADDR_LEN {
|
||||
return Err(anyhow!(
|
||||
"invalid MAC {} (length {}, expected {})",
|
||||
s,
|
||||
v.len(),
|
||||
MAC_ADDR_LEN
|
||||
));
|
||||
}
|
||||
|
||||
for i in 0..MAC_ADDR_LEN {
|
||||
if v[i].len() != 2 {
|
||||
return Err(anyhow!(
|
||||
"invalid MAC {} (segment {} length {}, expected {})",
|
||||
s,
|
||||
i,
|
||||
v.len(),
|
||||
2
|
||||
));
|
||||
}
|
||||
|
||||
bytes[i] =
|
||||
u8::from_str_radix(v[i], 16).context(format!("failed to parse MAC address: {}", s))?;
|
||||
}
|
||||
|
||||
Ok(MacAddr { bytes })
|
||||
}
|
481
src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs
Normal file
481
src/runtime-rs/crates/hypervisor/ch-config/src/lib.rs
Normal file
@ -0,0 +1,481 @@
|
||||
// Copyright (c) 2022-2023 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub mod ch_api;
|
||||
pub mod net_util;
|
||||
mod virtio_devices;
|
||||
|
||||
use crate::virtio_devices::RateLimiterConfig;
|
||||
pub use net_util::MacAddr;
|
||||
|
||||
pub const MAX_NUM_PCI_SEGMENTS: u16 = 16;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct BalloonConfig {
|
||||
pub size: u64,
|
||||
/// Option to deflate the balloon in case the guest is out of memory.
|
||||
#[serde(default)]
|
||||
pub deflate_on_oom: bool,
|
||||
/// Option to enable free page reporting from the guest.
|
||||
#[serde(default)]
|
||||
pub free_page_reporting: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct CmdlineConfig {
|
||||
pub args: String,
|
||||
}
|
||||
|
||||
impl CmdlineConfig {
|
||||
fn is_empty(&self) -> bool {
|
||||
self.args.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct ConsoleConfig {
|
||||
//#[serde(default = "default_consoleconfig_file")]
|
||||
pub file: Option<PathBuf>,
|
||||
pub mode: ConsoleOutputMode,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub enum ConsoleOutputMode {
|
||||
#[default]
|
||||
Off,
|
||||
Pty,
|
||||
Tty,
|
||||
File,
|
||||
Null,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpuAffinity {
|
||||
pub vcpu: u8,
|
||||
pub host_cpus: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpusConfig {
|
||||
pub boot_vcpus: u8,
|
||||
pub max_vcpus: u8,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub topology: Option<CpuTopology>,
|
||||
#[serde(default)]
|
||||
pub kvm_hyperv: bool,
|
||||
#[serde(skip_serializing_if = "u8_is_zero")]
|
||||
pub max_phys_bits: u8,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub affinity: Option<Vec<CpuAffinity>>,
|
||||
#[serde(default)]
|
||||
pub features: CpuFeatures,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct CpuFeatures {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[serde(default)]
|
||||
pub amx: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct CpuTopology {
|
||||
pub threads_per_core: u8,
|
||||
pub cores_per_die: u8,
|
||||
pub dies_per_package: u8,
|
||||
pub packages: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct DeviceConfig {
|
||||
pub path: PathBuf,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct DiskConfig {
|
||||
pub path: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub readonly: bool,
|
||||
#[serde(default)]
|
||||
pub direct: bool,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
//#[serde(default = "default_diskconfig_num_queues")]
|
||||
pub num_queues: usize,
|
||||
//#[serde(default = "default_diskconfig_queue_size")]
|
||||
pub queue_size: u16,
|
||||
#[serde(default)]
|
||||
pub vhost_user: bool,
|
||||
pub vhost_socket: Option<String>,
|
||||
#[serde(default)]
|
||||
pub rate_limiter_config: Option<RateLimiterConfig>,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
// For testing use only. Not exposed in API.
|
||||
#[serde(default)]
|
||||
pub disable_io_uring: bool,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct FsConfig {
|
||||
pub tag: String,
|
||||
pub socket: PathBuf,
|
||||
//#[serde(default = "default_fsconfig_num_queues")]
|
||||
pub num_queues: usize,
|
||||
//#[serde(default = "default_fsconfig_queue_size")]
|
||||
pub queue_size: u16,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub enum HotplugMethod {
|
||||
#[default]
|
||||
Acpi,
|
||||
VirtioMem,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct InitramfsConfig {
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct KernelConfig {
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct MemoryConfig {
|
||||
pub size: u64,
|
||||
#[serde(default)]
|
||||
pub mergeable: bool,
|
||||
#[serde(default)]
|
||||
pub hotplug_method: HotplugMethod,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hotplug_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hotplugged_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub shared: bool,
|
||||
#[serde(default)]
|
||||
pub hugepages: bool,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub hugepage_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub prefault: bool,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub zones: Option<Vec<MemoryZoneConfig>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct MemoryZoneConfig {
|
||||
pub id: String,
|
||||
pub size: u64,
|
||||
#[serde(default)]
|
||||
pub file: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub shared: bool,
|
||||
#[serde(default)]
|
||||
pub hugepages: bool,
|
||||
#[serde(default)]
|
||||
pub hugepage_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub host_numa_node: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub hotplug_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub hotplugged_size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub prefault: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub struct NetConfig {
|
||||
//#[serde(default = "default_netconfig_tap")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tap: Option<String>,
|
||||
//#[serde(default = "default_netconfig_ip")]
|
||||
pub ip: Ipv4Addr,
|
||||
//#[serde(default = "default_netconfig_mask")]
|
||||
pub mask: Ipv4Addr,
|
||||
//#[serde(default = "default_netconfig_mac")]
|
||||
pub mac: MacAddr,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub host_mac: Option<MacAddr>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mtu: Option<u16>,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
//#[serde(default = "default_netconfig_num_queues")]
|
||||
#[serde(skip_serializing_if = "usize_is_zero")]
|
||||
pub num_queues: usize,
|
||||
//#[serde(default = "default_netconfig_queue_size")]
|
||||
#[serde(skip_serializing_if = "u16_is_zero")]
|
||||
pub queue_size: u16,
|
||||
#[serde(default)]
|
||||
pub vhost_user: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub vhost_socket: Option<String>,
|
||||
#[serde(default)]
|
||||
pub vhost_mode: VhostMode,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub fds: Option<Vec<i32>>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rate_limiter_config: Option<RateLimiterConfig>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "u16_is_zero")]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
impl Default for NetConfig {
|
||||
fn default() -> Self {
|
||||
NetConfig {
|
||||
tap: None,
|
||||
ip: Ipv4Addr::new(0, 0, 0, 0),
|
||||
mask: Ipv4Addr::new(0, 0, 0, 0),
|
||||
mac: MacAddr::default(),
|
||||
host_mac: None,
|
||||
mtu: None,
|
||||
iommu: false,
|
||||
num_queues: 0,
|
||||
queue_size: 0,
|
||||
vhost_user: false,
|
||||
vhost_socket: None,
|
||||
vhost_mode: VhostMode::default(),
|
||||
id: None,
|
||||
fds: None,
|
||||
rate_limiter_config: None,
|
||||
pci_segment: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct NumaConfig {
|
||||
#[serde(default)]
|
||||
pub guest_numa_id: u32,
|
||||
#[serde(default)]
|
||||
pub cpus: Option<Vec<u8>>,
|
||||
#[serde(default)]
|
||||
pub distances: Option<Vec<NumaDistance>>,
|
||||
#[serde(default)]
|
||||
pub memory_zones: Option<Vec<String>>,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[serde(default)]
|
||||
pub sgx_epc_sections: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct NumaDistance {
|
||||
#[serde(default)]
|
||||
pub destination: u32,
|
||||
#[serde(default)]
|
||||
pub distance: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
pub struct PayloadConfig {
|
||||
#[serde(default)]
|
||||
pub firmware: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub kernel: Option<PathBuf>,
|
||||
#[serde(default)]
|
||||
pub cmdline: Option<String>,
|
||||
#[serde(default)]
|
||||
pub initramfs: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct PlatformConfig {
|
||||
//#[serde(default = "default_platformconfig_num_pci_segments")]
|
||||
pub num_pci_segments: u16,
|
||||
#[serde(default)]
|
||||
pub iommu_segments: Option<Vec<u16>>,
|
||||
#[serde(default)]
|
||||
pub serial_number: Option<String>,
|
||||
#[serde(default)]
|
||||
pub uuid: Option<String>,
|
||||
#[serde(default)]
|
||||
pub oem_strings: Option<Vec<String>>,
|
||||
#[cfg(feature = "tdx")]
|
||||
#[serde(default)]
|
||||
pub tdx: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct PmemConfig {
|
||||
pub file: PathBuf,
|
||||
#[serde(default)]
|
||||
pub size: Option<u64>,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
#[serde(default)]
|
||||
pub discard_writes: bool,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct RngConfig {
|
||||
pub src: PathBuf,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct SgxEpcConfig {
|
||||
pub id: String,
|
||||
#[serde(default)]
|
||||
pub size: u64,
|
||||
#[serde(default)]
|
||||
pub prefault: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct UserDeviceConfig {
|
||||
pub socket: PathBuf,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct VdpaConfig {
|
||||
pub path: PathBuf,
|
||||
//#[serde(default = "default_vdpaconfig_num_queues")]
|
||||
pub num_queues: usize,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub enum VhostMode {
|
||||
#[default]
|
||||
Client,
|
||||
Server,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct VmConfig {
|
||||
#[serde(default)]
|
||||
pub cpus: CpusConfig,
|
||||
#[serde(default)]
|
||||
pub memory: MemoryConfig,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub kernel: Option<KernelConfig>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub initramfs: Option<InitramfsConfig>,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "CmdlineConfig::is_empty")]
|
||||
pub cmdline: CmdlineConfig,
|
||||
#[serde(default)]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub payload: Option<PayloadConfig>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub disks: Option<Vec<DiskConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub net: Option<Vec<NetConfig>>,
|
||||
#[serde(default)]
|
||||
pub rng: RngConfig,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub balloon: Option<BalloonConfig>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub fs: Option<Vec<FsConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub pmem: Option<Vec<PmemConfig>>,
|
||||
//#[serde(default = "ConsoleConfig::default_serial")]
|
||||
pub serial: ConsoleConfig,
|
||||
//#[serde(default = "ConsoleConfig::default_console")]
|
||||
pub console: ConsoleConfig,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub devices: Option<Vec<DeviceConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub user_devices: Option<Vec<UserDeviceConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub vdpa: Option<Vec<VdpaConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub vsock: Option<VsockConfig>,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub sgx_epc: Option<Vec<SgxEpcConfig>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub numa: Option<Vec<NumaConfig>>,
|
||||
#[serde(default)]
|
||||
pub watchdog: bool,
|
||||
#[cfg(feature = "guest_debug")]
|
||||
pub gdb: bool,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub platform: Option<PlatformConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, Default)]
|
||||
pub struct VsockConfig {
|
||||
pub cid: u64,
|
||||
pub socket: PathBuf,
|
||||
#[serde(default)]
|
||||
pub iommu: bool,
|
||||
#[serde(default)]
|
||||
pub id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub pci_segment: u16,
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// For serde serialization
|
||||
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn u8_is_zero(v: &u8) -> bool {
|
||||
*v == 0
|
||||
}
|
||||
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn usize_is_zero(v: &usize) -> bool {
|
||||
*v == 0
|
||||
}
|
||||
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
fn u16_is_zero(v: &u16) -> bool {
|
||||
*v == 0
|
||||
}
|
32
src/runtime-rs/crates/hypervisor/ch-config/src/net_util.rs
Normal file
32
src/runtime-rs/crates/hypervisor/ch-config/src/net_util.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2022-2023 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use std::fmt;
|
||||
|
||||
pub const MAC_ADDR_LEN: usize = 6;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Default)]
|
||||
pub struct MacAddr {
|
||||
pub bytes: [u8; MAC_ADDR_LEN],
|
||||
}
|
||||
|
||||
// Note: Implements ToString automatically.
|
||||
impl fmt::Display for MacAddr {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let b = &self.bytes;
|
||||
write!(
|
||||
f,
|
||||
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
|
||||
b[0], b[1], b[2], b[3], b[4], b[5]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Requried to remove the `bytes` member from the serialized JSON!
|
||||
impl Serialize for MacAddr {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
self.to_string().serialize(serializer)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2022-2023 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct TokenBucketConfig {
|
||||
pub size: u64,
|
||||
pub one_time_burst: Option<u64>,
|
||||
pub refill_time: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RateLimiterConfig {
|
||||
pub bandwidth: Option<TokenBucketConfig>,
|
||||
pub ops: Option<TokenBucketConfig>,
|
||||
}
|
148
src/runtime-rs/crates/hypervisor/src/ch/inner.rs
Normal file
148
src/runtime-rs/crates/hypervisor/src/ch/inner.rs
Normal file
@ -0,0 +1,148 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::HypervisorState;
|
||||
use crate::device::Device;
|
||||
use crate::VmmState;
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
||||
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||
use kata_types::config::hypervisor::HYPERVISOR_NAME_CH;
|
||||
use persist::sandbox_persist::Persist;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use tokio::process::Child;
|
||||
use tokio::sync::watch::{channel, Receiver, Sender};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CloudHypervisorInner {
|
||||
pub(crate) state: VmmState,
|
||||
pub(crate) id: String,
|
||||
|
||||
pub(crate) api_socket: Option<UnixStream>,
|
||||
pub(crate) extra_args: Option<Vec<String>>,
|
||||
|
||||
pub(crate) config: Option<HypervisorConfig>,
|
||||
|
||||
pub(crate) process: Option<Child>,
|
||||
pub(crate) pid: Option<u32>,
|
||||
|
||||
pub(crate) timeout_secs: i32,
|
||||
|
||||
pub(crate) netns: Option<String>,
|
||||
|
||||
// Sandbox-specific directory
|
||||
pub(crate) vm_path: String,
|
||||
|
||||
// Hypervisor runtime directory
|
||||
pub(crate) run_dir: String,
|
||||
|
||||
// Subdirectory of vm_path.
|
||||
pub(crate) jailer_root: String,
|
||||
|
||||
/// List of devices that will be added to the VM once it boots
|
||||
pub(crate) pending_devices: Option<Vec<Device>>,
|
||||
|
||||
pub(crate) _capabilities: Capabilities,
|
||||
|
||||
pub(crate) shutdown_tx: Option<Sender<bool>>,
|
||||
pub(crate) shutdown_rx: Option<Receiver<bool>>,
|
||||
pub(crate) tasks: Option<Vec<JoinHandle<Result<()>>>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for CloudHypervisorInner {}
|
||||
unsafe impl Sync for CloudHypervisorInner {}
|
||||
|
||||
const CH_DEFAULT_TIMEOUT_SECS: u32 = 10;
|
||||
|
||||
impl CloudHypervisorInner {
|
||||
pub fn new() -> Self {
|
||||
let mut capabilities = Capabilities::new();
|
||||
capabilities.set(
|
||||
CapabilityBits::BlockDeviceSupport
|
||||
| CapabilityBits::BlockDeviceHotplugSupport
|
||||
| CapabilityBits::FsSharingSupport,
|
||||
);
|
||||
|
||||
let (tx, rx) = channel(true);
|
||||
|
||||
Self {
|
||||
api_socket: None,
|
||||
extra_args: None,
|
||||
|
||||
process: None,
|
||||
pid: None,
|
||||
|
||||
config: None,
|
||||
state: VmmState::NotReady,
|
||||
timeout_secs: CH_DEFAULT_TIMEOUT_SECS as i32,
|
||||
id: String::default(),
|
||||
jailer_root: String::default(),
|
||||
vm_path: String::default(),
|
||||
run_dir: String::default(),
|
||||
netns: None,
|
||||
pending_devices: None,
|
||||
_capabilities: capabilities,
|
||||
shutdown_tx: Some(tx),
|
||||
shutdown_rx: Some(rx),
|
||||
tasks: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_hypervisor_config(&mut self, config: HypervisorConfig) {
|
||||
self.config = Some(config);
|
||||
}
|
||||
|
||||
pub fn hypervisor_config(&self) -> HypervisorConfig {
|
||||
self.config.clone().unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CloudHypervisorInner {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Persist for CloudHypervisorInner {
|
||||
type State = HypervisorState;
|
||||
type ConstructorArgs = ();
|
||||
|
||||
// Return a state object that will be saved by the caller.
|
||||
async fn save(&self) -> Result<Self::State> {
|
||||
Ok(HypervisorState {
|
||||
hypervisor_type: HYPERVISOR_NAME_CH.to_string(),
|
||||
id: self.id.clone(),
|
||||
vm_path: self.vm_path.clone(),
|
||||
jailed: false,
|
||||
jailer_root: String::default(),
|
||||
netns: None,
|
||||
config: self.hypervisor_config(),
|
||||
run_dir: self.run_dir.clone(),
|
||||
cached_block_devices: Default::default(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
// Set the hypervisor state to the specified state
|
||||
async fn restore(
|
||||
_hypervisor_args: Self::ConstructorArgs,
|
||||
hypervisor_state: Self::State,
|
||||
) -> Result<Self> {
|
||||
let ch = Self {
|
||||
config: Some(hypervisor_state.config),
|
||||
state: VmmState::NotReady,
|
||||
id: hypervisor_state.id,
|
||||
vm_path: hypervisor_state.vm_path,
|
||||
run_dir: hypervisor_state.run_dir,
|
||||
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(ch)
|
||||
}
|
||||
}
|
235
src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs
Normal file
235
src/runtime-rs/crates/hypervisor/src/ch/inner_device.rs
Normal file
@ -0,0 +1,235 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2019-2022 Ant Group
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::inner::CloudHypervisorInner;
|
||||
use crate::device::{Device, ShareFsDeviceConfig};
|
||||
use crate::HybridVsockConfig;
|
||||
use crate::VmmState;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use ch_config::ch_api::cloud_hypervisor_vm_fs_add;
|
||||
use ch_config::{FsConfig, PmemConfig};
|
||||
use safe_path::scoped_join;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const VIRTIO_FS: &str = "virtio-fs";
|
||||
|
||||
impl CloudHypervisorInner {
|
||||
pub(crate) async fn add_device(&mut self, device: Device) -> Result<()> {
|
||||
if self.state != VmmState::VmRunning {
|
||||
let mut devices: Vec<Device> = if let Some(devices) = self.pending_devices.take() {
|
||||
devices
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
devices.insert(0, device);
|
||||
|
||||
self.pending_devices = Some(devices);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.handle_add_device(device).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_add_device(&mut self, device: Device) -> Result<()> {
|
||||
match device {
|
||||
Device::ShareFsDevice(cfg) => self.handle_share_fs_device(cfg).await,
|
||||
Device::HybridVsock(cfg) => self.handle_hvsock_device(&cfg).await,
|
||||
_ => return Err(anyhow!("unhandled device: {:?}", device)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Add the device that were requested to be added before the VMM was
|
||||
/// started.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) async fn handle_pending_devices_after_boot(&mut self) -> Result<()> {
|
||||
if self.state != VmmState::VmRunning {
|
||||
return Err(anyhow!(
|
||||
"cannot handle pending devices with VMM state {:?}",
|
||||
self.state
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(mut devices) = self.pending_devices.take() {
|
||||
while let Some(dev) = devices.pop() {
|
||||
self.add_device(dev).await.context("add_device")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn remove_device(&mut self, _device: Device) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_share_fs_device(&mut self, cfg: ShareFsDeviceConfig) -> Result<()> {
|
||||
if cfg.fs_type != VIRTIO_FS {
|
||||
return Err(anyhow!("cannot handle share fs type: {:?}", cfg.fs_type));
|
||||
}
|
||||
|
||||
let socket = self
|
||||
.api_socket
|
||||
.as_ref()
|
||||
.ok_or("missing socket")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let num_queues: usize = if cfg.queue_num > 0 {
|
||||
cfg.queue_num as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let queue_size: u16 = if cfg.queue_num > 0 {
|
||||
u16::try_from(cfg.queue_size)?
|
||||
} else {
|
||||
1024
|
||||
};
|
||||
|
||||
let socket_path = if cfg.sock_path.starts_with('/') {
|
||||
PathBuf::from(cfg.sock_path)
|
||||
} else {
|
||||
scoped_join(&self.vm_path, cfg.sock_path)?
|
||||
};
|
||||
|
||||
let fs_config = FsConfig {
|
||||
tag: cfg.mount_tag,
|
||||
socket: socket_path,
|
||||
num_queues,
|
||||
queue_size,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let response = cloud_hypervisor_vm_fs_add(
|
||||
socket.try_clone().context("failed to clone socket")?,
|
||||
fs_config,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(detail) = response {
|
||||
debug!(sl!(), "fs add response: {:?}", detail);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_hvsock_device(&mut self, _cfg: &HybridVsockConfig) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_shared_fs_devices(&mut self) -> Result<Option<Vec<FsConfig>>> {
|
||||
let pending_root_devices = self.pending_devices.take();
|
||||
|
||||
let mut root_devices = Vec::<FsConfig>::new();
|
||||
|
||||
if let Some(devices) = pending_root_devices {
|
||||
for dev in devices {
|
||||
match dev {
|
||||
Device::ShareFsDevice(dev) => {
|
||||
let settings = ShareFsSettings::new(dev, self.vm_path.clone());
|
||||
|
||||
let fs_cfg = FsConfig::try_from(settings)?;
|
||||
|
||||
root_devices.push(fs_cfg);
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Some(root_devices))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_boot_file(&mut self) -> Result<PathBuf> {
|
||||
if let Some(ref config) = self.config {
|
||||
let boot_info = &config.boot_info;
|
||||
|
||||
let file = if !boot_info.initrd.is_empty() {
|
||||
boot_info.initrd.clone()
|
||||
} else if !boot_info.image.is_empty() {
|
||||
boot_info.image.clone()
|
||||
} else {
|
||||
return Err(anyhow!("missing boot file (no image or initrd)"));
|
||||
};
|
||||
|
||||
Ok(PathBuf::from(file))
|
||||
} else {
|
||||
Err(anyhow!("no hypervisor config"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn get_pmem_devices(&mut self) -> Result<Option<Vec<PmemConfig>>> {
|
||||
let file = self.get_boot_file().await?;
|
||||
|
||||
let pmem_cfg = PmemConfig {
|
||||
file,
|
||||
size: None,
|
||||
iommu: false,
|
||||
discard_writes: true,
|
||||
id: None,
|
||||
pci_segment: 0,
|
||||
};
|
||||
|
||||
let pmem_devices = vec![pmem_cfg];
|
||||
|
||||
Ok(Some(pmem_devices))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ShareFsSettings {
|
||||
cfg: ShareFsDeviceConfig,
|
||||
vm_path: String,
|
||||
}
|
||||
|
||||
impl ShareFsSettings {
|
||||
pub fn new(cfg: ShareFsDeviceConfig, vm_path: String) -> Self {
|
||||
ShareFsSettings { cfg, vm_path }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<ShareFsSettings> for FsConfig {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(settings: ShareFsSettings) -> Result<Self, Self::Error> {
|
||||
let cfg = settings.cfg;
|
||||
let vm_path = settings.vm_path;
|
||||
|
||||
let num_queues: usize = if cfg.queue_num > 0 {
|
||||
cfg.queue_num as usize
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
let queue_size: u16 = if cfg.queue_num > 0 {
|
||||
u16::try_from(cfg.queue_size)?
|
||||
} else {
|
||||
1024
|
||||
};
|
||||
|
||||
let socket_path = if cfg.sock_path.starts_with('/') {
|
||||
PathBuf::from(cfg.sock_path)
|
||||
} else {
|
||||
PathBuf::from(vm_path).join(cfg.sock_path)
|
||||
};
|
||||
|
||||
let fs_cfg = FsConfig {
|
||||
tag: cfg.mount_tag,
|
||||
socket: socket_path,
|
||||
num_queues,
|
||||
queue_size,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Ok(fs_cfg)
|
||||
}
|
||||
}
|
486
src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs
Normal file
486
src/runtime-rs/crates/hypervisor/src/ch/inner_hypervisor.rs
Normal file
@ -0,0 +1,486 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::inner::CloudHypervisorInner;
|
||||
use crate::ch::utils::get_api_socket_path;
|
||||
use crate::ch::utils::{get_jailer_root, get_sandbox_path, get_vsock_path};
|
||||
use crate::Device;
|
||||
use crate::VsockConfig;
|
||||
use crate::{VcpuThreadIds, VmmState};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use ch_config::ch_api::{
|
||||
cloud_hypervisor_vm_create, cloud_hypervisor_vm_start, cloud_hypervisor_vmm_ping,
|
||||
cloud_hypervisor_vmm_shutdown,
|
||||
};
|
||||
use core::future::poll_fn;
|
||||
use futures::executor::block_on;
|
||||
use futures::future::join_all;
|
||||
use kata_types::capabilities::{Capabilities, CapabilityBits};
|
||||
use std::fs::create_dir_all;
|
||||
use std::os::unix::net::UnixStream;
|
||||
use std::path::Path;
|
||||
use std::process::Stdio;
|
||||
use tokio::io::AsyncBufReadExt;
|
||||
use tokio::io::BufReader;
|
||||
use tokio::process::{Child, Command};
|
||||
use tokio::sync::watch::Receiver;
|
||||
use tokio::task;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio::time::Duration;
|
||||
|
||||
const CH_NAME: &str = "cloud-hypervisor";
|
||||
|
||||
/// Number of milliseconds to wait before retrying a CH operation.
|
||||
const CH_POLL_TIME_MS: u64 = 50;
|
||||
|
||||
impl CloudHypervisorInner {
|
||||
async fn start_hypervisor(&mut self, timeout_secs: i32) -> Result<()> {
|
||||
self.cloud_hypervisor_launch(timeout_secs)
|
||||
.await
|
||||
.context("launch failed")?;
|
||||
|
||||
self.cloud_hypervisor_setup_comms()
|
||||
.await
|
||||
.context("comms setup failed")?;
|
||||
|
||||
self.cloud_hypervisor_check_running()
|
||||
.await
|
||||
.context("hypervisor running check failed")?;
|
||||
|
||||
self.state = VmmState::VmmServerReady;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn boot_vm(&mut self) -> Result<()> {
|
||||
let shared_fs_devices = self.get_shared_fs_devices().await?;
|
||||
|
||||
let pmem_devices = self.get_pmem_devices().await?;
|
||||
|
||||
let socket = self
|
||||
.api_socket
|
||||
.as_ref()
|
||||
.ok_or("missing socket")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let sandbox_path = get_sandbox_path(&self.id)?;
|
||||
|
||||
std::fs::create_dir_all(sandbox_path.clone()).context("failed to create sandbox path")?;
|
||||
|
||||
let vsock_socket_path = get_vsock_path(&self.id)?;
|
||||
|
||||
let response = cloud_hypervisor_vm_create(
|
||||
sandbox_path,
|
||||
vsock_socket_path,
|
||||
socket.try_clone().context("failed to clone socket")?,
|
||||
shared_fs_devices,
|
||||
pmem_devices,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(detail) = response {
|
||||
debug!(sl!(), "vm boot response: {:?}", detail);
|
||||
}
|
||||
|
||||
let response =
|
||||
cloud_hypervisor_vm_start(socket.try_clone().context("failed to clone socket")?)
|
||||
.await?;
|
||||
|
||||
if let Some(detail) = response {
|
||||
debug!(sl!(), "vm start response: {:?}", detail);
|
||||
}
|
||||
|
||||
self.state = VmmState::VmRunning;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_setup_comms(&mut self) -> Result<()> {
|
||||
let api_socket_path = get_api_socket_path(&self.id)?;
|
||||
|
||||
// The hypervisor has just been spawned, but may not yet have created
|
||||
// the API socket, so repeatedly try to connect for up to
|
||||
// timeout_secs.
|
||||
let join_handle: JoinHandle<Result<UnixStream>> =
|
||||
task::spawn_blocking(move || -> Result<UnixStream> {
|
||||
let api_socket: UnixStream;
|
||||
|
||||
loop {
|
||||
let result = UnixStream::connect(api_socket_path.clone());
|
||||
|
||||
if let Ok(result) = result {
|
||||
api_socket = result;
|
||||
break;
|
||||
}
|
||||
|
||||
std::thread::sleep(Duration::from_millis(CH_POLL_TIME_MS));
|
||||
}
|
||||
|
||||
Ok(api_socket)
|
||||
});
|
||||
|
||||
let timeout_msg = format!(
|
||||
"API socket connect timed out after {} seconds",
|
||||
self.timeout_secs
|
||||
);
|
||||
|
||||
let result =
|
||||
tokio::time::timeout(Duration::from_secs(self.timeout_secs as u64), join_handle)
|
||||
.await
|
||||
.context(timeout_msg)?;
|
||||
|
||||
let result = result?;
|
||||
|
||||
let api_socket = result?;
|
||||
|
||||
self.api_socket = Some(api_socket);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_check_running(&mut self) -> Result<()> {
|
||||
let timeout_secs = self.timeout_secs;
|
||||
|
||||
let timeout_msg = format!(
|
||||
"API socket connect timed out after {} seconds",
|
||||
timeout_secs
|
||||
);
|
||||
|
||||
let join_handle = self.cloud_hypervisor_ping_until_ready(CH_POLL_TIME_MS);
|
||||
|
||||
let result = tokio::time::timeout(Duration::new(timeout_secs as u64, 0), join_handle)
|
||||
.await
|
||||
.context(timeout_msg)?;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_ensure_not_launched(&self) -> Result<()> {
|
||||
if let Some(child) = &self.process {
|
||||
return Err(anyhow!(
|
||||
"{} already running with PID {}",
|
||||
CH_NAME,
|
||||
child.id().unwrap_or(0)
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_launch(&mut self, _timeout_secs: i32) -> Result<()> {
|
||||
self.cloud_hypervisor_ensure_not_launched().await?;
|
||||
|
||||
let debug = false;
|
||||
|
||||
let disable_seccomp = true;
|
||||
|
||||
let api_socket_path = get_api_socket_path(&self.id)?;
|
||||
|
||||
let _ = std::fs::remove_file(api_socket_path.clone());
|
||||
|
||||
let binary_path = self
|
||||
.config
|
||||
.as_ref()
|
||||
.ok_or("no hypervisor config for CH")
|
||||
.map_err(|e| anyhow!(e))?
|
||||
.path
|
||||
.to_string();
|
||||
|
||||
let path = Path::new(&binary_path).canonicalize()?;
|
||||
|
||||
let mut cmd = Command::new(path);
|
||||
|
||||
cmd.current_dir("/");
|
||||
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stdout(Stdio::piped());
|
||||
cmd.stderr(Stdio::piped());
|
||||
|
||||
cmd.env("RUST_BACKTRACE", "full");
|
||||
|
||||
cmd.args(["--api-socket", &api_socket_path]);
|
||||
|
||||
if let Some(extra_args) = &self.extra_args {
|
||||
cmd.args(extra_args);
|
||||
}
|
||||
|
||||
if debug {
|
||||
cmd.arg("-v");
|
||||
}
|
||||
|
||||
if disable_seccomp {
|
||||
cmd.args(["--seccomp", "false"]);
|
||||
}
|
||||
|
||||
let child = cmd.spawn().context(format!("{} spawn failed", CH_NAME))?;
|
||||
|
||||
// Save process PID
|
||||
self.pid = child.id();
|
||||
|
||||
let shutdown = self
|
||||
.shutdown_rx
|
||||
.as_ref()
|
||||
.ok_or("no receiver channel")
|
||||
.map_err(|e| anyhow!(e))?
|
||||
.clone();
|
||||
|
||||
let ch_outputlogger_task = tokio::spawn(cloud_hypervisor_log_output(child, shutdown));
|
||||
|
||||
let tasks = vec![ch_outputlogger_task];
|
||||
|
||||
self.tasks = Some(tasks);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_shutdown(&mut self) -> Result<()> {
|
||||
let socket = self
|
||||
.api_socket
|
||||
.as_ref()
|
||||
.ok_or("missing socket")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let response =
|
||||
cloud_hypervisor_vmm_shutdown(socket.try_clone().context("shutdown failed")?).await?;
|
||||
|
||||
if let Some(detail) = response {
|
||||
debug!(sl!(), "shutdown response: {:?}", detail);
|
||||
}
|
||||
|
||||
// Trigger a controlled shutdown
|
||||
self.shutdown_tx
|
||||
.as_mut()
|
||||
.ok_or("no shutdown channel")
|
||||
.map_err(|e| anyhow!(e))?
|
||||
.send(true)
|
||||
.map_err(|e| anyhow!(e).context("failed to request shutdown"))?;
|
||||
|
||||
let tasks = self
|
||||
.tasks
|
||||
.take()
|
||||
.ok_or("no tasks")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let results = join_all(tasks).await;
|
||||
|
||||
let mut wait_errors: Vec<tokio::task::JoinError> = vec![];
|
||||
|
||||
for result in results {
|
||||
if let Err(e) = result {
|
||||
eprintln!("wait task error: {:#?}", e);
|
||||
|
||||
wait_errors.push(e);
|
||||
}
|
||||
}
|
||||
|
||||
if wait_errors.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("wait all tasks failed: {:#?}", wait_errors))
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
async fn cloud_hypervisor_wait(&mut self) -> Result<()> {
|
||||
let mut child = self
|
||||
.process
|
||||
.take()
|
||||
.ok_or(format!("{} not running", CH_NAME))
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let _pid = child
|
||||
.id()
|
||||
.ok_or(format!("{} missing PID", CH_NAME))
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
// Note that this kills _and_ waits for the process!
|
||||
child.kill().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn cloud_hypervisor_ping_until_ready(&mut self, _poll_time_ms: u64) -> Result<()> {
|
||||
let socket = self
|
||||
.api_socket
|
||||
.as_ref()
|
||||
.ok_or("missing socket")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
loop {
|
||||
let response =
|
||||
cloud_hypervisor_vmm_ping(socket.try_clone().context("failed to clone socket")?)
|
||||
.await
|
||||
.context("ping failed");
|
||||
|
||||
if let Ok(response) = response {
|
||||
if let Some(detail) = response {
|
||||
debug!(sl!(), "ping response: {:?}", detail);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(CH_POLL_TIME_MS)).await;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn prepare_vm(&mut self, id: &str, netns: Option<String>) -> Result<()> {
|
||||
self.id = id.to_string();
|
||||
self.state = VmmState::NotReady;
|
||||
|
||||
self.setup_environment().await?;
|
||||
|
||||
self.netns = netns;
|
||||
|
||||
let vsock_cfg = VsockConfig::new(self.id.clone()).await?;
|
||||
|
||||
let dev = Device::Vsock(vsock_cfg);
|
||||
self.add_device(dev).await.context("add vsock device")?;
|
||||
|
||||
self.start_hypervisor(self.timeout_secs).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn setup_environment(&mut self) -> Result<()> {
|
||||
// run_dir and vm_path are the same (shared)
|
||||
self.run_dir = get_sandbox_path(&self.id)?;
|
||||
self.vm_path = self.run_dir.to_string();
|
||||
|
||||
create_dir_all(&self.run_dir)
|
||||
.with_context(|| anyhow!("failed to create sandbox directory {}", self.run_dir))?;
|
||||
|
||||
if !self.jailer_root.is_empty() {
|
||||
create_dir_all(self.jailer_root.as_str())
|
||||
.map_err(|e| anyhow!("Failed to create dir {} err : {:?}", self.jailer_root, e))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn start_vm(&mut self, timeout_secs: i32) -> Result<()> {
|
||||
self.setup_environment().await?;
|
||||
|
||||
self.timeout_secs = timeout_secs;
|
||||
|
||||
self.boot_vm().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn stop_vm(&mut self) -> Result<()> {
|
||||
block_on(self.cloud_hypervisor_shutdown())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn pause_vm(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn resume_vm(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn save_vm(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_agent_socket(&self) -> Result<String> {
|
||||
const HYBRID_VSOCK_SCHEME: &str = "hvsock";
|
||||
|
||||
let vsock_path = get_vsock_path(&self.id)?;
|
||||
|
||||
let uri = format!("{}://{}", HYBRID_VSOCK_SCHEME, vsock_path);
|
||||
|
||||
Ok(uri)
|
||||
}
|
||||
|
||||
pub(crate) async fn disconnect(&mut self) {
|
||||
self.state = VmmState::NotReady;
|
||||
}
|
||||
|
||||
pub(crate) async fn get_thread_ids(&self) -> Result<VcpuThreadIds> {
|
||||
Ok(VcpuThreadIds::default())
|
||||
}
|
||||
|
||||
pub(crate) async fn cleanup(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_pids(&self) -> Result<Vec<u32>> {
|
||||
Ok(Vec::<u32>::new())
|
||||
}
|
||||
|
||||
pub(crate) async fn check(&self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn get_jailer_root(&self) -> Result<String> {
|
||||
let root_path = get_jailer_root(&self.id)?;
|
||||
|
||||
std::fs::create_dir_all(&root_path)?;
|
||||
|
||||
Ok(root_path)
|
||||
}
|
||||
|
||||
pub(crate) async fn capabilities(&self) -> Result<Capabilities> {
|
||||
let mut caps = Capabilities::default();
|
||||
caps.set(CapabilityBits::FsSharingSupport);
|
||||
Ok(caps)
|
||||
}
|
||||
}
|
||||
|
||||
// Log all output from the CH process until a shutdown signal is received.
|
||||
// When that happens, stop logging and wait for the child process to finish
|
||||
// before returning.
|
||||
async fn cloud_hypervisor_log_output(mut child: Child, mut shutdown: Receiver<bool>) -> Result<()> {
|
||||
let stdout = child
|
||||
.stdout
|
||||
.as_mut()
|
||||
.ok_or("failed to get child stdout")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let stdout_reader = BufReader::new(stdout);
|
||||
let mut stdout_lines = stdout_reader.lines();
|
||||
|
||||
let stderr = child
|
||||
.stderr
|
||||
.as_mut()
|
||||
.ok_or("failed to get child stderr")
|
||||
.map_err(|e| anyhow!(e))?;
|
||||
|
||||
let stderr_reader = BufReader::new(stderr);
|
||||
let mut stderr_lines = stderr_reader.lines();
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = shutdown.changed() => {
|
||||
info!(sl!(), "got shutdown request");
|
||||
break;
|
||||
},
|
||||
stderr_line = poll_fn(|cx| Pin::new(&mut stderr_lines).poll_next_line(cx)) => {
|
||||
if let Ok(line) = stderr_line {
|
||||
let line = line.ok_or("missing stderr line").map_err(|e| anyhow!(e))?;
|
||||
|
||||
info!(sl!(), "{:?}", line; "stream" => "stderr");
|
||||
}
|
||||
},
|
||||
stdout_line = poll_fn(|cx| Pin::new(&mut stdout_lines).poll_next_line(cx)) => {
|
||||
if let Ok(line) = stdout_line {
|
||||
let line = line.ok_or("missing stdout line").map_err(|e| anyhow!(e))?;
|
||||
|
||||
info!(sl!(), "{:?}", line; "stream" => "stdout");
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Note that this kills _and_ waits for the process!
|
||||
child.kill().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
163
src/runtime-rs/crates/hypervisor/src/ch/mod.rs
Normal file
163
src/runtime-rs/crates/hypervisor/src/ch/mod.rs
Normal file
@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2019-2022 Alibaba Cloud
|
||||
// Copyright (c) 2022 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use super::HypervisorState;
|
||||
use crate::{device::Device, Hypervisor, VcpuThreadIds};
|
||||
use anyhow::{Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use kata_types::capabilities::Capabilities;
|
||||
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||
use persist::sandbox_persist::Persist;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
// Convenience macro to obtain the scope logger
|
||||
#[macro_export]
|
||||
macro_rules! sl {
|
||||
() => {
|
||||
slog_scope::logger().new(o!("subsystem" => "cloud-hypervisor"))
|
||||
};
|
||||
}
|
||||
|
||||
mod inner;
|
||||
mod inner_device;
|
||||
mod inner_hypervisor;
|
||||
mod utils;
|
||||
|
||||
use inner::CloudHypervisorInner;
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct CloudHypervisor {
|
||||
inner: Arc<RwLock<CloudHypervisorInner>>,
|
||||
}
|
||||
|
||||
unsafe impl Send for CloudHypervisor {}
|
||||
unsafe impl Sync for CloudHypervisor {}
|
||||
|
||||
impl CloudHypervisor {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(RwLock::new(CloudHypervisorInner::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_hypervisor_config(&mut self, config: HypervisorConfig) {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.set_hypervisor_config(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Hypervisor for CloudHypervisor {
|
||||
async fn prepare_vm(&self, id: &str, netns: Option<String>) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.prepare_vm(id, netns).await
|
||||
}
|
||||
|
||||
async fn start_vm(&self, timeout: i32) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.start_vm(timeout).await
|
||||
}
|
||||
|
||||
async fn stop_vm(&self) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.stop_vm()
|
||||
}
|
||||
|
||||
async fn pause_vm(&self) -> Result<()> {
|
||||
let inner = self.inner.write().await;
|
||||
inner.pause_vm()
|
||||
}
|
||||
|
||||
async fn resume_vm(&self) -> Result<()> {
|
||||
let inner = self.inner.write().await;
|
||||
inner.resume_vm()
|
||||
}
|
||||
|
||||
async fn save_vm(&self) -> Result<()> {
|
||||
let inner = self.inner.write().await;
|
||||
inner.save_vm().await
|
||||
}
|
||||
|
||||
async fn add_device(&self, device: Device) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.add_device(device).await
|
||||
}
|
||||
|
||||
async fn remove_device(&self, device: Device) -> Result<()> {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.remove_device(device).await
|
||||
}
|
||||
|
||||
async fn get_agent_socket(&self) -> Result<String> {
|
||||
let inner = self.inner.write().await;
|
||||
inner.get_agent_socket().await
|
||||
}
|
||||
|
||||
async fn disconnect(&self) {
|
||||
let mut inner = self.inner.write().await;
|
||||
inner.disconnect().await
|
||||
}
|
||||
|
||||
async fn hypervisor_config(&self) -> HypervisorConfig {
|
||||
let inner = self.inner.write().await;
|
||||
inner.hypervisor_config()
|
||||
}
|
||||
|
||||
async fn get_thread_ids(&self) -> Result<VcpuThreadIds> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.get_thread_ids().await
|
||||
}
|
||||
|
||||
async fn cleanup(&self) -> Result<()> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.cleanup().await
|
||||
}
|
||||
|
||||
async fn get_pids(&self) -> Result<Vec<u32>> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.get_pids().await
|
||||
}
|
||||
|
||||
async fn check(&self) -> Result<()> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.check().await
|
||||
}
|
||||
|
||||
async fn get_jailer_root(&self) -> Result<String> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.get_jailer_root().await
|
||||
}
|
||||
|
||||
async fn save_state(&self) -> Result<HypervisorState> {
|
||||
self.save().await
|
||||
}
|
||||
|
||||
async fn capabilities(&self) -> Result<Capabilities> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.capabilities().await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Persist for CloudHypervisor {
|
||||
type State = HypervisorState;
|
||||
type ConstructorArgs = ();
|
||||
|
||||
async fn save(&self) -> Result<Self::State> {
|
||||
let inner = self.inner.read().await;
|
||||
inner.save().await.context("save CH hypervisor state")
|
||||
}
|
||||
|
||||
async fn restore(
|
||||
hypervisor_args: Self::ConstructorArgs,
|
||||
hypervisor_state: Self::State,
|
||||
) -> Result<Self> {
|
||||
let inner = CloudHypervisorInner::restore(hypervisor_args, hypervisor_state).await?;
|
||||
Ok(Self {
|
||||
inner: Arc::new(RwLock::new(inner)),
|
||||
})
|
||||
}
|
||||
}
|
53
src/runtime-rs/crates/hypervisor/src/ch/utils.rs
Normal file
53
src/runtime-rs/crates/hypervisor/src/ch/utils.rs
Normal file
@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2022-2023 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anyhow::Result;
|
||||
use shim_interface::KATA_PATH;
|
||||
|
||||
// The socket used to connect to CH. This is used for CH API communications.
|
||||
const CH_API_SOCKET_NAME: &str = "ch-api.sock";
|
||||
|
||||
// The socket that allows runtime-rs to connect direct through to the Kata
|
||||
// Containers agent running inside the CH hosted VM.
|
||||
const CH_VM_SOCKET_NAME: &str = "ch-vm.sock";
|
||||
|
||||
const CH_JAILER_DIR: &str = "root";
|
||||
|
||||
// Return the path for a _hypothetical_ sandbox: the path does *not* exist
|
||||
// yet, and for this reason safe-path cannot be used.
|
||||
pub fn get_sandbox_path(id: &str) -> Result<String> {
|
||||
let path = [KATA_PATH, id].join("/");
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
// Return the path for a _hypothetical_ API socket path:
|
||||
// the path does *not* exist yet, and for this reason safe-path cannot be
|
||||
// used.
|
||||
pub fn get_api_socket_path(id: &str) -> Result<String> {
|
||||
let sandbox_path = get_sandbox_path(id)?;
|
||||
|
||||
let path = [&sandbox_path, CH_API_SOCKET_NAME].join("/");
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
// Return the path for a _hypothetical_ sandbox specific VSOCK socket path:
|
||||
// the path does *not* exist yet, and for this reason safe-path cannot be
|
||||
// used.
|
||||
pub fn get_vsock_path(id: &str) -> Result<String> {
|
||||
let sandbox_path = get_sandbox_path(id)?;
|
||||
|
||||
let path = [&sandbox_path, CH_VM_SOCKET_NAME].join("/");
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
|
||||
pub fn get_jailer_root(id: &str) -> Result<String> {
|
||||
let sandbox_path = get_sandbox_path(id)?;
|
||||
|
||||
let path = [&sandbox_path, CH_JAILER_DIR].join("/");
|
||||
|
||||
Ok(path)
|
||||
}
|
@ -8,7 +8,7 @@ use crate::HypervisorConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
#[derive(Serialize, Deserialize, Default, Clone, Debug)]
|
||||
pub struct HypervisorState {
|
||||
// Type of hypervisor, E.g. dragonball/qemu/firecracker/acrn.
|
||||
pub hypervisor_type: String,
|
||||
|
@ -19,11 +19,17 @@ pub use kernel_param::Param;
|
||||
mod utils;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(feature = "cloud-hypervisor")]
|
||||
pub mod ch;
|
||||
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use hypervisor_persist::HypervisorState;
|
||||
use kata_types::capabilities::Capabilities;
|
||||
use kata_types::config::hypervisor::Hypervisor as HypervisorConfig;
|
||||
|
||||
pub use kata_types::config::hypervisor::HYPERVISOR_NAME_CH;
|
||||
|
||||
// Config which driver to use as vm root dev
|
||||
const VM_ROOTFS_DRIVER_BLK: &str = "virtio-blk";
|
||||
const VM_ROOTFS_DRIVER_PMEM: &str = "virtio-pmem";
|
||||
@ -48,7 +54,7 @@ const SHMEM: &str = "shmem";
|
||||
pub const HYPERVISOR_DRAGONBALL: &str = "dragonball";
|
||||
pub const HYPERVISOR_QEMU: &str = "qemu";
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub(crate) enum VmmState {
|
||||
NotReady,
|
||||
VmmServerReady,
|
||||
@ -56,7 +62,7 @@ pub(crate) enum VmmState {
|
||||
}
|
||||
|
||||
// vcpu mapping from vcpu number to thread number
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct VcpuThreadIds {
|
||||
pub vcpus: HashMap<u32, u32>,
|
||||
}
|
||||
|
@ -35,3 +35,9 @@ oci = { path = "../../../../libs/oci" }
|
||||
persist = { path = "../../persist"}
|
||||
resource = { path = "../../resource" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
# Feature is not yet complete, so not enabled by default.
|
||||
# See https://github.com/kata-containers/kata-containers/issues/6264.
|
||||
cloud-hypervisor = []
|
||||
|
@ -25,6 +25,12 @@ use hypervisor::{qemu::Qemu, HYPERVISOR_QEMU};
|
||||
use kata_types::config::{
|
||||
hypervisor::register_hypervisor_plugin, DragonballConfig, QemuConfig, TomlConfig,
|
||||
};
|
||||
|
||||
#[cfg(feature = "cloud-hypervisor")]
|
||||
use hypervisor::ch::CloudHypervisor;
|
||||
#[cfg(feature = "cloud-hypervisor")]
|
||||
use kata_types::config::{hypervisor::HYPERVISOR_NAME_CH, CloudHypervisorConfig};
|
||||
|
||||
use resource::ResourceManager;
|
||||
use sandbox::VIRTCONTAINER;
|
||||
use tokio::sync::mpsc::Sender;
|
||||
@ -39,8 +45,16 @@ impl RuntimeHandler for VirtContainer {
|
||||
// register
|
||||
let dragonball_config = Arc::new(DragonballConfig::new());
|
||||
register_hypervisor_plugin("dragonball", dragonball_config);
|
||||
|
||||
let qemu_config = Arc::new(QemuConfig::new());
|
||||
register_hypervisor_plugin("qemu", qemu_config);
|
||||
|
||||
#[cfg(feature = "cloud-hypervisor")]
|
||||
{
|
||||
let ch_config = Arc::new(CloudHypervisorConfig::new());
|
||||
register_hypervisor_plugin(HYPERVISOR_NAME_CH, ch_config);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -118,6 +132,17 @@ async fn new_hypervisor(toml_config: &TomlConfig) -> Result<Arc<dyn Hypervisor>>
|
||||
.await;
|
||||
Ok(Arc::new(hypervisor))
|
||||
}
|
||||
|
||||
#[cfg(feature = "cloud-hypervisor")]
|
||||
HYPERVISOR_NAME_CH => {
|
||||
let mut hypervisor = CloudHypervisor::new();
|
||||
|
||||
hypervisor
|
||||
.set_hypervisor_config(hypervisor_config.clone())
|
||||
.await;
|
||||
|
||||
Ok(Arc::new(hypervisor))
|
||||
}
|
||||
_ => Err(anyhow!("Unsupported hypervisor {}", &hypervisor_name)),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user