Skip to content

Commit

Permalink
runtime-rs: build qemu params for QmpSocket and refine new method
Browse files Browse the repository at this point in the history
Fixies: kata-containers#9603

Signed-off-by: Alex Lyn <alex.lyn@antgroup.com>
  • Loading branch information
Apokleos committed May 15, 2024
1 parent ee276c8 commit 6e46fe5
Showing 1 changed file with 72 additions and 10 deletions.
82 changes: 72 additions & 10 deletions src/runtime-rs/crates/hypervisor/src/qemu/cmdline_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ 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, PathBuf};
use tokio;

// These should have been called MiB and GiB for better readability but the
// more fitting names unfortunately generate linter warnings.
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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -1217,30 +1222,88 @@ impl ToString for MonitorProtocol {
}
}

#[derive(Debug)]
pub enum QemuSockType {
Fd(File),
Path(PathBuf),
}

impl Clone for QemuSockType {
fn clone(&self) -> Self {
match self {
QemuSockType::Fd(file) => QemuSockType::Fd(file.try_clone().unwrap()),
QemuSockType::Path(name) => QemuSockType::Path(name.clone()),
}
}
}

#[derive(Debug)]
pub struct QmpSocket {
// protocol to be used on the socket.
pub protocol: MonitorProtocol,
// QMP listener file descriptor to be passed to qemu
pub fd: File,
// QMP listener address to be passed to qemu
pub address: QemuSockType,
// server tells if this is a server socket.
pub server: bool,
// nowait tells if qemu should block waiting for a client to connect.
pub nowait: bool,
}

impl QmpSocket {
fn new() -> Result<Vec<Self>> {
let qmp_sockets: Vec<QmpSocket> = Vec::new();
let _proto = MonitorProtocol::new("qmp");
fn new(sid: &str, extra_monitor: bool) -> Result<Vec<Self>> {
let mut qmp_sockets: Vec<QmpSocket> = Vec::new();

let root_path = Path::new(KATA_PATH).join(sid);

// The default QMP socket or called base socket is qmp.sock, its fd will be passed.
let sock_path = root_path.join(QMP_SOCKET_FILE);
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_file = unsafe { File::from_raw_fd(raw_fd) };

qmp_sockets.push(QmpSocket {
protocol: MonitorProtocol::new("qmp"),
address: QemuSockType::Fd(sock_file),
server: true,
nowait: true,
});

// If extra monitor needed, HMP socket with qmp-extra.sock will be added.
if extra_monitor {
qmp_sockets.push(QmpSocket {
protocol: MonitorProtocol::new("hmp"),
address: QemuSockType::Path(root_path.join(QMP_EXTRA_SOCKET_FILE)),
server: true,
nowait: true,
});
}

Ok(qmp_sockets)
}
}

#[async_trait]
impl ToQemuParams for QmpSocket {
async fn qemu_params(&self) -> Result<Vec<String>> {
Ok(vec![])
let mut params: Vec<String> = Vec::new();

// -qmp unix:fd=SOCK_FD,server=on,wait=off
// -monitor unix:path=EXTRA_SOCK_PATH,server=on,wait=off
let param_qmp = format!("-{}", self.protocol.to_string());
match self.address.clone() {
QemuSockType::Fd(f) => params.push(format!("unix:fd={}", f.as_raw_fd())),
QemuSockType::Path(p) => params.push(format!("unix:path={}", p.display().to_string())),
}

if self.server {
params.push("server=on".to_owned());
if self.nowait {
params.push("wait=off".to_owned());
}
}

Ok(vec![param_qmp, params.join(",")])
}
}

Expand Down Expand Up @@ -1297,8 +1360,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(),
};
Expand Down

0 comments on commit 6e46fe5

Please sign in to comment.