diff --git a/src/main.rs b/src/main.rs index 9bec0eee6..fa86cd47a 100755 --- a/src/main.rs +++ b/src/main.rs @@ -137,7 +137,8 @@ fn create_app<'a, 'b>( "Network parameters \"tap=,\ ip=,mask=,mac=,\ iommu=on|off,num_queues=,\ - queue_size=\"", + queue_size=,\ + vhost_user=,socket=\"", ) .takes_value(true) .min_values(1) diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index 18705ca02..c9a1192a0 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -307,6 +307,11 @@ components: queue_size: type: integer default: 256 + vhost_user: + type: boolean + default: false + vhost_socket: + type: string RngConfig: required: diff --git a/vmm/src/config.rs b/vmm/src/config.rs index a47c2a2b0..7353ffe2f 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -55,6 +55,10 @@ pub enum Error { ParseNetNumQueuesParam(std::num::ParseIntError), /// Failed parsing network queue size parameter. ParseNetQueueSizeParam(std::num::ParseIntError), + /// Failed to parse vhost parameters + ParseNetVhostParam(std::str::ParseBoolError), + /// Need a vhost socket + ParseNetVhostSocketRequired, /// Failed parsing fs tag parameter. ParseFsTagParam, /// Failed parsing fs socket path parameter. @@ -431,6 +435,9 @@ pub struct NetConfig { pub num_queues: usize, #[serde(default = "default_netconfig_queue_size")] pub queue_size: u16, + #[serde(default)] + pub vhost_user: bool, + pub vhost_socket: Option, } fn default_netconfig_tap() -> Option { @@ -469,6 +476,8 @@ impl NetConfig { let mut iommu_str: &str = ""; let mut num_queues_str: &str = ""; let mut queue_size_str: &str = ""; + let mut vhost_socket_str: &str = ""; + let mut vhost_user_str: &str = ""; for param in params_list.iter() { if param.starts_with("tap=") { @@ -485,6 +494,10 @@ impl NetConfig { num_queues_str = ¶m[11..]; } else if param.starts_with("queue_size=") { queue_size_str = ¶m[11..]; + } else if param.starts_with("vhost_user=") { + vhost_user_str = ¶m[11..]; + } else if param.starts_with("socket=") { + vhost_socket_str = ¶m[7..]; } } @@ -495,6 +508,8 @@ impl NetConfig { let iommu = parse_on_off(iommu_str)?; let mut num_queues: usize = default_netconfig_num_queues(); let mut queue_size: u16 = default_netconfig_queue_size(); + let mut vhost_user = false; + let mut vhost_socket = None; if !tap_str.is_empty() { tap = Some(tap_str.to_string()); @@ -518,6 +533,17 @@ impl NetConfig { .parse() .map_err(Error::ParseNetQueueSizeParam)?; } + if !vhost_user_str.is_empty() { + vhost_user = vhost_user_str.parse().map_err(Error::ParseNetVhostParam)?; + } + if !vhost_socket_str.is_empty() { + 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, @@ -527,6 +553,8 @@ impl NetConfig { iommu, num_queues, queue_size, + vhost_user, + vhost_socket, }) } } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index e45ad5815..53800677a 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -1032,49 +1032,67 @@ impl DeviceManager { Ok(devices) } + /// Add virto-net and vhost-user-net devices fn make_virtio_net_devices( vm_info: &VmInfo, migratable_devices: &mut Vec>>, ) -> DeviceManagerResult> { let mut devices = Vec::new(); - // Add virtio-net if required if let Some(net_list_cfg) = &vm_info.vm_cfg.lock().unwrap().net { for net_cfg in net_list_cfg.iter() { - let virtio_net_device = if let Some(ref tap_if_name) = net_cfg.tap { - Arc::new(Mutex::new( - vm_virtio::Net::new( - Some(tap_if_name), - None, - None, - Some(net_cfg.mac), - net_cfg.iommu, - net_cfg.num_queues, - net_cfg.queue_size, - ) - .map_err(DeviceManagerError::CreateVirtioNet)?, - )) + if net_cfg.vhost_user { + let vu_cfg = VhostUserConfig { + sock: net_cfg.vhost_socket.clone().unwrap(), + num_queues: net_cfg.num_queues, + queue_size: net_cfg.queue_size, + }; + let vhost_user_net_device = Arc::new(Mutex::new( + vm_virtio::vhost_user::Net::new(net_cfg.mac, vu_cfg) + .map_err(DeviceManagerError::CreateVhostUserNet)?, + )); + devices.push(( + Arc::clone(&vhost_user_net_device) + as Arc>, + net_cfg.iommu, + )); + migratable_devices + .push(Arc::clone(&vhost_user_net_device) as Arc>); } else { - Arc::new(Mutex::new( - vm_virtio::Net::new( - None, - Some(net_cfg.ip), - Some(net_cfg.mask), - Some(net_cfg.mac), - net_cfg.iommu, - net_cfg.num_queues, - net_cfg.queue_size, - ) - .map_err(DeviceManagerError::CreateVirtioNet)?, - )) - }; - - devices.push(( - Arc::clone(&virtio_net_device) as Arc>, - net_cfg.iommu, - )); - migratable_devices - .push(Arc::clone(&virtio_net_device) as Arc>); + let virtio_net_device = if let Some(ref tap_if_name) = net_cfg.tap { + Arc::new(Mutex::new( + vm_virtio::Net::new( + Some(tap_if_name), + None, + None, + Some(net_cfg.mac), + net_cfg.iommu, + net_cfg.num_queues, + net_cfg.queue_size, + ) + .map_err(DeviceManagerError::CreateVirtioNet)?, + )) + } else { + Arc::new(Mutex::new( + vm_virtio::Net::new( + None, + Some(net_cfg.ip), + Some(net_cfg.mask), + Some(net_cfg.mac), + net_cfg.iommu, + net_cfg.num_queues, + net_cfg.queue_size, + ) + .map_err(DeviceManagerError::CreateVirtioNet)?, + )) + }; + devices.push(( + Arc::clone(&virtio_net_device) as Arc>, + net_cfg.iommu, + )); + migratable_devices + .push(Arc::clone(&virtio_net_device) as Arc>); + } } }