vmm: Add support for spawning vhost-user-net backend

If no socket is supplied when enabling "vhost_user=true" on "--net"
follow the "exe" path in the /proc entry for this process and launch the
network backend (via the vmm_path field.)

Currently this only supports creating a new tap interface as the network
backend also only supports that.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2020-02-04 16:44:12 +00:00
parent d054dddcb3
commit bc75c1b4e1
5 changed files with 62 additions and 12 deletions

1
Cargo.lock generated
View File

@ -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",

View File

@ -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"

View File

@ -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,

View File

@ -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<T> = result::Result<T, DeviceManagerError>;
@ -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<AddressManager>,
@ -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<ActivatedBackend>,
}
impl DeviceManager {
@ -413,7 +434,7 @@ impl DeviceManager {
memory_manager: Arc<Mutex<MemoryManager>>,
_exit_evt: &EventFd,
reset_evt: &EventFd,
_vmm_path: PathBuf,
vmm_path: PathBuf,
) -> DeviceManagerResult<Self> {
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<String> {
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<Vec<(VirtioDeviceArc, bool)>> {
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,
};

View File

@ -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};