diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs index da775ecc72..32ec6bc0ca 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs @@ -3,19 +3,21 @@ // SPDX-License-Identifier: Apache-2.0 // -use anyhow::{anyhow, Context, Result}; - +use super::cmdline_generator::QemuCmdLine; use crate::{ - hypervisor_persist::HypervisorState, HypervisorConfig, MemoryConfig, - VcpuThreadIds, VsockDevice, HYPERVISOR_QEMU, + hypervisor_persist::HypervisorState, HypervisorConfig, MemoryConfig, VcpuThreadIds, + VsockDevice, HYPERVISOR_QEMU, }; +use anyhow::{anyhow, Result}; +use async_trait::async_trait; use kata_types::{ capabilities::{Capabilities, CapabilityBits}, config::KATA_PATH, }; -use async_trait::async_trait; -use std::collections::HashMap; use persist::sandbox_persist::Persist; +use std::collections::HashMap; +use std::os::unix::io::AsRawFd; +use std::process::Child; const VSOCK_SCHEME: &str = "vsock"; @@ -24,6 +26,8 @@ pub struct QemuInner { /// sandbox id id: String, + qemu_process: Option, + config: HypervisorConfig, devices: Vec, } @@ -32,6 +36,7 @@ impl QemuInner { pub fn new() -> QemuInner { QemuInner { id: "".to_string(), + qemu_process: None, config: Default::default(), devices: Vec::new(), } @@ -39,15 +44,8 @@ impl QemuInner { pub(crate) async fn prepare_vm(&mut self, id: &str, _netns: Option) -> Result<()> { info!(sl!(), "Preparing QEMU VM"); - self.id = id.to_string(); - self.devices.push(DeviceType::Vsock( - VsockDevice::new(self.id.clone()) - .await - .context("qemu: create agent vsock")?, - )); - Ok(()) } @@ -57,28 +55,72 @@ impl QemuInner { let vm_path = [KATA_PATH, self.id.as_str()].join("/"); std::fs::create_dir_all(vm_path)?; + let mut cmdline = QemuCmdLine::new(&self.id, &self.config)?; + + // If there's a Vsock Device in `self.devices` the vhost-vsock file + // descriptor needs to stay open until the qemu process launches. + // This is why we need to store it in a variable at this scope. + let mut _vhost_fd = None; + + for device in &mut self.devices { + match device { + DeviceType::ShareFs(share_fs_dev) => { + if share_fs_dev.config.fs_type == "virtio-fs" { + cmdline.add_virtiofs_share( + &share_fs_dev.config.sock_path, + &share_fs_dev.config.mount_tag, + share_fs_dev.config.queue_size, + ); + } + } + DeviceType::Vsock(vsock_dev) => { + let fd = vsock_dev.init_config().await?; + cmdline.add_vsock(fd.as_raw_fd(), vsock_dev.config.guest_cid)?; + _vhost_fd = Some(fd); + } + DeviceType::Block(block_dev) => { + if block_dev.config.path_on_host == self.config.boot_info.initrd { + // If this block device represents initrd we ignore it here, it + // will be handled elsewhere by adding `-initrd` to the qemu + // command line. + continue; + } + match block_dev.config.driver_option.as_str() { + "nvdimm" => cmdline.add_nvdimm( + &block_dev.config.path_on_host, + block_dev.config.is_readonly, + )?, + unsupported => { + info!(sl!(), "unsupported block device driver: {}", unsupported) + } + } + } + _ => info!(sl!(), "qemu cmdline: unsupported device: {:?}", device), + } + } + // To get access to the VM console for debugging, enable the following + // line and replace its argument appropriately (open a terminal, run + // `tty` in it to get its device file path and use it as the argument). + //cmdline.add_serial_console("/dev/pts/23"); + + info!(sl!(), "qemu args: {}", cmdline.build().await?.join(" ")); let mut command = std::process::Command::new(&self.config.path); + command.args(cmdline.build().await?); - command - .arg("-kernel") - .arg(&self.config.boot_info.kernel) - .arg("-m") - .arg(format!("{}M", &self.config.memory_info.default_memory)) - .arg("-initrd") - .arg(&self.config.boot_info.initrd) - .arg("-vga") - .arg("none") - .arg("-nodefaults") - .arg("-nographic"); - - command.spawn()?; + info!(sl!(), "qemu cmd: {:?}", command); + self.qemu_process = Some(command.spawn()?); Ok(()) } pub(crate) fn stop_vm(&mut self) -> Result<()> { info!(sl!(), "Stopping QEMU VM"); - todo!() + if let Some(ref mut qemu_process) = &mut self.qemu_process { + info!(sl!(), "QemuInner::stop_vm(): kill()'ing qemu"); + qemu_process.kill().map_err(anyhow::Error::from) + } else { + Err(anyhow!("qemu process not running")) + } } pub(crate) fn pause_vm(&self) -> Result<()> { @@ -121,7 +163,16 @@ impl QemuInner { pub(crate) async fn get_vmm_master_tid(&self) -> Result { info!(sl!(), "QemuInner::get_vmm_master_tid()"); - todo!() + if let Some(qemu_process) = &self.qemu_process { + info!( + sl!(), + "QemuInner::get_vmm_master_tid(): returning {}", + qemu_process.id() + ); + Ok(qemu_process.id()) + } else { + Err(anyhow!("qemu process not running")) + } } pub(crate) async fn get_ns_path(&self) -> Result { @@ -237,11 +288,7 @@ impl QemuInner { fn get_agent_vsock_dev(&self) -> Option<&VsockDevice> { self.devices.iter().find_map(|dev| { if let DeviceType::Vsock(vsock_dev) = dev { - if vsock_dev.id == self.id { - Some(vsock_dev) - } else { - None - } + Some(vsock_dev) } else { None } diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/mod.rs b/src/runtime-rs/crates/hypervisor/src/qemu/mod.rs index 7b712f140c..16921fcee1 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/mod.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/mod.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 // +mod cmdline_generator; mod inner; use crate::device::DeviceType;