diff --git a/Cargo.lock b/Cargo.lock index 42c700130..3ff32a718 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1212,6 +1212,7 @@ dependencies = [ "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "signal-hook 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "vfio 0.0.1", "vm-allocator 0.1.0", "vm-device 0.1.0", diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 75b8ae0f0..5b220cfff 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -37,6 +37,7 @@ vm-device = { path = "../vm-device" } vm-virtio = { path = "../vm-virtio" } vmm-sys-util = ">=0.3.1" signal-hook = "0.1.13" +tempfile = "3.1.0" [dependencies.linux-loader] git = "https://github.com/rust-vmm/linux-loader" diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 6193c73eb..28fcb7387 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -587,11 +587,6 @@ impl NetConfig { vhost_socket = Some(vhost_socket_str.to_owned()); } - // For now we require a socket if vhost-user is turned on - if vhost_user && vhost_socket.is_none() { - return Err(Error::ParseNetVhostSocketRequired); - } - Ok(NetConfig { tap, ip, diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 39ce4d0d0..4e29cc87d 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -12,7 +12,7 @@ extern crate vm_device; use crate::config::ConsoleOutputMode; -use crate::config::VmConfig; +use crate::config::{NetConfig, VmConfig}; use crate::interrupt::{ KvmLegacyUserspaceInterruptManager, KvmMsiInterruptManager, KvmRoutingEntry, }; @@ -40,6 +40,7 @@ use std::result; #[cfg(feature = "pci_support")] use std::sync::Weak; use std::sync::{Arc, Mutex}; +use tempfile::NamedTempFile; #[cfg(feature = "pci_support")] use vfio::{VfioDevice, VfioDmaMapping, VfioPciDevice, VfioPciError}; use vm_allocator::SystemAllocator; @@ -197,6 +198,12 @@ pub enum DeviceManagerError { /// Failed cloning a File. CloneFile(io::Error), + + /// Failed to create socket file + CreateSocketFile(io::Error), + + /// Failed to spawn the network backend + SpawnNetBackend(io::Error), } pub type DeviceManagerResult = result::Result; @@ -366,6 +373,17 @@ impl DeviceRelocation for AddressManager { } } +struct ActivatedBackend { + _socket_file: tempfile::NamedTempFile, + child: std::process::Child, +} + +impl Drop for ActivatedBackend { + fn drop(&mut self) { + self.child.wait().ok(); + } +} + pub struct DeviceManager { // Manage address space related to devices address_manager: Arc, @@ -402,7 +420,10 @@ pub struct DeviceManager { virtio_devices: Vec<(VirtioDeviceArc, bool)>, // The path to the VMM for self spawning - _vmm_path: PathBuf, + vmm_path: PathBuf, + + // Backends that have been spawned + vhost_user_backends: Vec, } impl DeviceManager { @@ -413,7 +434,7 @@ impl DeviceManager { memory_manager: Arc>, _exit_evt: &EventFd, reset_evt: &EventFd, - _vmm_path: PathBuf, + vmm_path: PathBuf, ) -> DeviceManagerResult { let io_bus = devices::Bus::new(); let mmio_bus = devices::Bus::new(); @@ -487,7 +508,8 @@ impl DeviceManager { migratable_devices, memory_manager, virtio_devices: Vec::new(), - _vmm_path, + vmm_path, + vhost_user_backends: Vec::new(), }; device_manager @@ -932,15 +954,45 @@ impl DeviceManager { Ok(devices) } + /// Launch network backend + fn start_net_backend(&mut self, net_cfg: &NetConfig) -> DeviceManagerResult { + let _socket_file = NamedTempFile::new().map_err(DeviceManagerError::CreateSocketFile)?; + let sock = _socket_file.path().to_str().unwrap().to_owned(); + + let child = std::process::Command::new(&self.vmm_path) + .args(&[ + "--net-backend", + &format!( + "ip={},mask={},sock={},num_queues={},queue_size={}", + net_cfg.ip, net_cfg.mask, &sock, net_cfg.num_queues, net_cfg.queue_size + ), + ]) + .spawn() + .map_err(DeviceManagerError::SpawnNetBackend)?; + + // The ActivatedBackend::drop() will automatically reap the child + self.vhost_user_backends.push(ActivatedBackend { + child, + _socket_file, + }); + + Ok(sock) + } + /// Add virto-net and vhost-user-net devices fn make_virtio_net_devices(&mut self) -> DeviceManagerResult> { let mut devices = Vec::new(); - - if let Some(net_list_cfg) = &self.config.lock().unwrap().net { + let net_devices = self.config.lock().unwrap().net.clone(); + if let Some(net_list_cfg) = &net_devices { for net_cfg in net_list_cfg.iter() { if net_cfg.vhost_user { + let sock = if let Some(sock) = net_cfg.vhost_socket.clone() { + sock + } else { + self.start_net_backend(net_cfg)? + }; let vu_cfg = VhostUserConfig { - sock: net_cfg.vhost_socket.clone().unwrap(), + sock, num_queues: net_cfg.num_queues, queue_size: net_cfg.queue_size, }; diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index e40e97a93..bce04caea 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -12,6 +12,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; +extern crate tempfile; extern crate vmm_sys_util; use crate::api::{ApiError, ApiRequest, ApiResponse, ApiResponsePayload, VmInfo, VmmPingResponse};