diff --git a/src/runtime-rs/Cargo.lock b/src/runtime-rs/Cargo.lock index f7b26af6ad..09c3210c7b 100644 --- a/src/runtime-rs/Cargo.lock +++ b/src/runtime-rs/Cargo.lock @@ -1644,6 +1644,9 @@ dependencies = [ "nix 0.24.3", "path-clean", "persist", + "qapi", + "qapi-qmp", + "qapi-spec", "rand 0.8.5", "rust-ini", "safe-path 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2959,6 +2962,65 @@ dependencies = [ "ttrpc-codegen", ] +[[package]] +name = "qapi" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6412bdd014ebee03ddbbe79ac03a0b622cce4d80ba45254f6357c847f06fa38" +dependencies = [ + "bytes", + "futures 0.3.28", + "log", + "memchr", + "qapi-qmp", + "qapi-spec", + "serde", + "serde_json", + "tokio", + "tokio-util", +] + +[[package]] +name = "qapi-codegen" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ba4de731473de4c8bd508ddb38a9049e999b8a7429f3c052ba8735a178ff68c" +dependencies = [ + "qapi-parser", +] + +[[package]] +name = "qapi-parser" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80044db145aa2953ef5803d0376dcbca50f2763242547e856b7f37507adca677" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "qapi-qmp" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b944db7e544d2fa97595e9a000a6ba5c62c426fa185e7e00aabe4b5640b538" +dependencies = [ + "qapi-codegen", + "qapi-spec", + "serde", +] + +[[package]] +name = "qapi-spec" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b360919a24ea5fc02fa762cb01bd8f43b643fee51c585f763257773b4dc5a9e8" +dependencies = [ + "base64 0.13.1", + "serde", + "serde_json", +] + [[package]] name = "quote" version = "1.0.35" diff --git a/src/runtime-rs/crates/hypervisor/Cargo.toml b/src/runtime-rs/crates/hypervisor/Cargo.toml index dc2f57e62f..472986af65 100644 --- a/src/runtime-rs/crates/hypervisor/Cargo.toml +++ b/src/runtime-rs/crates/hypervisor/Cargo.toml @@ -43,6 +43,10 @@ safe-path = "0.1.0" crossbeam-channel = "0.5.6" tempdir = "0.3.7" +qapi = { version = "0.14", features = [ "qmp", "async-tokio-all" ] } +qapi-spec = "0.3.1" +qapi-qmp = "0.14.0" + [target.'cfg(not(target_arch = "s390x"))'.dependencies] dragonball = { path = "../../../dragonball", features = ["atomic-guest-memory", "virtio-vsock", "hotplug", "virtio-blk", "virtio-net", "virtio-fs", "vhost-net", "dbs-upcall", "virtio-mem", "virtio-balloon", "vhost-user-net", "host-device"] } diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs new file mode 100644 index 0000000000..615dc4cdcb --- /dev/null +++ b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs @@ -0,0 +1,40 @@ +// Copyright (c) 2024 Red Hat +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::Result; +use std::io::BufReader; +use std::os::unix::net::UnixStream; +use std::time::Duration; + +pub struct Qmp { + qmp: qapi::Qmp, UnixStream>>, +} + +impl Qmp { + pub fn new(qmp_sock_path: &str) -> Result { + let stream = UnixStream::connect(qmp_sock_path)?; + + // Set the read timeout to protect runtime-rs from blocking forever + // trying to set up QMP connection if qemu fails to launch. The exact + // value is a matter of judegement. Setting it too long would risk + // being ineffective since container runtime would timeout first anyway + // (containerd's task creation timeout is 2 s by default). OTOH + // setting it too short would risk interfering with a normal launch, + // perhaps just seeing some delay due to a heavily loaded host. + stream.set_read_timeout(Some(Duration::from_millis(250)))?; + + let mut qmp = Qmp { + qmp: qapi::Qmp::new(qapi::Stream::new( + BufReader::new(stream.try_clone()?), + stream, + )), + }; + + let info = qmp.qmp.handshake()?; + info!(sl!(), "QMP initialized: {:#?}", info); + + Ok(qmp) + } +}