diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs b/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs index da39fc87ea82..747079e26f75 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs @@ -8,10 +8,13 @@ use crate::{kernel_param::KernelParams, Address, HypervisorConfig}; use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; +use kata_types::config::KATA_PATH; use std::collections::HashMap; use std::fmt::Display; use std::fs::{read_to_string, File}; -use std::os::fd::AsRawFd; +use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd}; +use std::os::unix::net::UnixListener; +use std::path::Path; use tokio; // These should have been called MiB and GiB for better readability but the @@ -19,6 +22,9 @@ use tokio; const MI_B: u64 = 1024 * 1024; const GI_B: u64 = 1024 * MI_B; +const QMP_SOCKET_FILE: &str = "qmp.sock"; +const QMP_EXTRA_SOCKET_FILE: &str = "qmp-extra.sock"; + // The approach taken here is inspired by govmm. We build structs, each // corresponding to a qemu command line parameter, like Kernel, or a device, // for instance MemoryBackendFile. Members of these structs mostly directly @@ -1184,7 +1190,6 @@ impl ToQemuParams for DeviceIntelIommu { // to create a QMP unix domain manageent socket, e.g., // -qmp unix:fd=SOCKFD,server=on,wait=off. #[derive(Debug, Default, PartialEq)] -#[allow(dead_code)] pub enum MonitorProtocol { // Socket using a human-friendly text-based protocol. Hmp, @@ -1230,9 +1235,32 @@ pub struct QmpSocket { } impl QmpSocket { - fn new() -> Result> { - let qmp_sockets: Vec = Vec::new(); - let _proto = MonitorProtocol::new("qmp"); + fn new(sid: &str, extra_monitor: bool) -> Result> { + let mut qmp_sockets: Vec = Vec::new(); + + // The default QMP socket or called base socket is qmp.sock + let mut socket_paths: Vec<(&str, &str)> = vec![("qmp", QMP_SOCKET_FILE)]; + // If extra monitor needed, HMP socket with qmp-extra.sock will be added. + if extra_monitor { + socket_paths.push(("hmp", QMP_EXTRA_SOCKET_FILE)); + } + + let root_path = Path::new(KATA_PATH).join(sid); + for (proto, sock_path) in socket_paths { + let sock_path = root_path.join(sock_path); + let listener = UnixListener::bind(sock_path).context("unix listener bind failed.")?; + + let raw_fd = listener.into_raw_fd(); + clear_cloexec(raw_fd).context("clearing unix listenser O_CLOEXEC failed")?; + let sock_rawfd = unsafe { File::from_raw_fd(raw_fd) }; + + qmp_sockets.push(QmpSocket { + protocol: MonitorProtocol::new(proto), + fd: sock_rawfd, + server: true, + nowait: true, + }); + } Ok(qmp_sockets) } } @@ -1240,7 +1268,21 @@ impl QmpSocket { #[async_trait] impl ToQemuParams for QmpSocket { async fn qemu_params(&self) -> Result> { - Ok(vec![]) + let mut params: Vec = Vec::new(); + + // -qmp unix:fd=SOCKFD,server=on,wait=off + // -monitor unix:fd=SOCKFD,server=on,wait=off + let param_qmp = format!("-{}", self.protocol.to_string()); + params.push(format!("unix:fd={}", self.fd.as_raw_fd())); + + if self.server { + params.push("server=on".to_owned()); + if self.nowait { + params.push("wait=off".to_owned()); + } + } + + Ok(vec![param_qmp, params.join(",")]) } } @@ -1297,8 +1339,7 @@ impl<'a> QemuCmdLine<'a> { machine: Machine::new(config), cpu: Cpu::new(config), rtc: Rtc::new(), - qmp_sockets: QmpSocket::new()?, - + qmp_sockets: QmpSocket::new(id, false)?, knobs: Knobs::new(config), devices: Vec::new(), };