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 <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford 2021-06-04 14:40:13 +00:00
parent 2e236c53c8
commit 7fbec7113e
2 changed files with 57 additions and 0 deletions

View File

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

View File

@ -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<Vec<&'a str>>,
pub user_devices: Option<Vec<&'a str>>,
pub vsock: Option<&'a str>,
#[cfg(target_arch = "x86_64")]
pub sgx_epc: Option<Vec<&'a str>>,
@ -280,6 +289,7 @@ impl<'a> VmParams<'a> {
let fs: Option<Vec<&str>> = args.values_of("fs").map(|x| x.collect());
let pmem: Option<Vec<&str>> = args.values_of("pmem").map(|x| x.collect());
let devices: Option<Vec<&str>> = args.values_of("device").map(|x| x.collect());
let user_devices: Option<Vec<&str>> = 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<Vec<&str>> = 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<String>,
}
impl UserDeviceConfig {
pub const SYNTAX: &'static str = "Userspace device socket=<socket_path>,id=<device_id>\"";
pub fn parse(user_device: &str) -> Result<Self> {
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<Vec<DeviceConfig>>,
pub user_devices: Option<Vec<UserDeviceConfig>>,
pub vsock: Option<VsockConfig>,
#[serde(default)]
pub iommu: bool,
@ -1952,6 +1988,16 @@ impl VmConfig {
devices = Some(device_config_list);
}
let mut user_devices: Option<Vec<UserDeviceConfig>> = 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<VsockConfig> = 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")]