From 7fbec7113eb676ce06bc7b2d07e9d4acbd11a411 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 4 Jun 2021 14:40:13 +0000 Subject: [PATCH] main, config: Add support for `--user-device` This allows the user to specify devices that are running in a different userspace process and communicated with vfio-user. Signed-off-by: Rob Bradford --- src/main.rs | 9 +++++++++ vmm/src/config.rs | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/main.rs b/src/main.rs index 4a2d65d5d..d2c7580eb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -279,6 +279,14 @@ fn create_app<'a, 'b>( .min_values(1) .group("vm-config"), ) + .arg( + Arg::with_name("user-device") + .long("user-device") + .help(config::UserDeviceConfig::SYNTAX) + .takes_value(true) + .min_values(1) + .group("vm-config"), + ) .arg( Arg::with_name("vsock") .long("vsock") @@ -656,6 +664,7 @@ mod unit_tests { iommu: false, }, devices: None, + user_devices: None, vsock: None, iommu: false, #[cfg(target_arch = "x86_64")] diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 67f24623d..583ab63f5 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -90,6 +90,10 @@ pub enum Error { #[cfg(feature = "tdx")] // No TDX firmware FirmwarePathMissing, + /// Failed to parse userspace device + ParseUserDevice(OptionParserError), + /// Missing socket for userspace device + ParseUserDeviceSocketMissing, } #[derive(Debug)] @@ -224,6 +228,10 @@ impl fmt::Display for Error { ParseRestoreSourceUrlMissing => { write!(f, "Error parsing --restore: source_url missing") } + ParseUserDeviceSocketMissing => { + write!(f, "Error parsing --user-device: socket missing") + } + ParseUserDevice(o) => write!(f, "Error parsing --user-device: {}", o), Validation(v) => write!(f, "Error validating configuration: {}", v), #[cfg(feature = "tdx")] ParseTdx(o) => write!(f, "Error parsing --tdx: {}", o), @@ -251,6 +259,7 @@ pub struct VmParams<'a> { pub serial: &'a str, pub console: &'a str, pub devices: Option>, + pub user_devices: Option>, pub vsock: Option<&'a str>, #[cfg(target_arch = "x86_64")] pub sgx_epc: Option>, @@ -280,6 +289,7 @@ impl<'a> VmParams<'a> { let fs: Option> = args.values_of("fs").map(|x| x.collect()); let pmem: Option> = args.values_of("pmem").map(|x| x.collect()); let devices: Option> = args.values_of("device").map(|x| x.collect()); + let user_devices: Option> = args.values_of("user-device").map(|x| x.collect()); let vsock: Option<&str> = args.value_of("vsock"); #[cfg(target_arch = "x86_64")] let sgx_epc: Option> = args.values_of("sgx-epc").map(|x| x.collect()); @@ -303,6 +313,7 @@ impl<'a> VmParams<'a> { serial, console, devices, + user_devices, vsock, #[cfg(target_arch = "x86_64")] sgx_epc, @@ -1533,6 +1544,30 @@ impl DeviceConfig { } } +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] +pub struct UserDeviceConfig { + pub socket: PathBuf, + #[serde(default)] + pub id: Option, +} + +impl UserDeviceConfig { + pub const SYNTAX: &'static str = "Userspace device socket=,id=\""; + pub fn parse(user_device: &str) -> Result { + let mut parser = OptionParser::new(); + parser.add("socket").add("id"); + parser.parse(user_device).map_err(Error::ParseUserDevice)?; + + let socket = parser + .get("socket") + .map(PathBuf::from) + .ok_or(Error::ParseUserDeviceSocketMissing)?; + + let id = parser.get("id"); + + Ok(UserDeviceConfig { socket, id }) + } +} #[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)] pub struct VsockConfig { pub cid: u64, @@ -1764,6 +1799,7 @@ pub struct VmConfig { #[serde(default = "ConsoleConfig::default_console")] pub console: ConsoleConfig, pub devices: Option>, + pub user_devices: Option>, pub vsock: Option, #[serde(default)] pub iommu: bool, @@ -1952,6 +1988,16 @@ impl VmConfig { devices = Some(device_config_list); } + let mut user_devices: Option> = None; + if let Some(user_device_list) = &vm_params.user_devices { + let mut user_device_config_list = Vec::new(); + for item in user_device_list.iter() { + let user_device_config = UserDeviceConfig::parse(item)?; + user_device_config_list.push(user_device_config); + } + user_devices = Some(user_device_config_list); + } + let mut vsock: Option = None; if let Some(vs) = &vm_params.vsock { let vsock_config = VsockConfig::parse(vs)?; @@ -2017,6 +2063,7 @@ impl VmConfig { serial, console, devices, + user_devices, vsock, iommu, #[cfg(target_arch = "x86_64")] @@ -2625,6 +2672,7 @@ mod tests { iommu: false, }, devices: None, + user_devices: None, vsock: None, iommu: false, #[cfg(target_arch = "x86_64")]