From 584a2cccee144a00ddf41249a9e54aac8ea398ed Mon Sep 17 00:00:00 2001 From: Cathy Zhang Date: Wed, 28 Aug 2019 18:01:01 +0800 Subject: [PATCH] vmm: Add vhost-user-net support Update vm configuration and device initial process to add vhost-user-net support. Signed-off-by: Cathy Zhang --- vmm/src/config.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++ vmm/src/vm.rs | 43 ++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index c7337ccd3..e30f9726c 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -3,6 +3,8 @@ // SPDX-License-Identifier: Apache-2.0 // +extern crate vm_virtio; + use linux_loader::cmdline::Cmdline; use net_util::MacAddr; use std::convert::From; @@ -11,6 +13,7 @@ use std::net::Ipv4Addr; use std::path::Path; use std::result; use vm_memory::GuestAddress; +use vm_virtio::vhost_user::VhostUserConfig; pub const DEFAULT_VCPUS: &str = "1"; pub const DEFAULT_MEMORY: &str = "size=512M"; @@ -58,6 +61,16 @@ pub enum Error<'a> { ParseConsoleParam, /// Both console and serial are tty. ParseTTYParam, + /// Failed parsing vhost-user-net mac parameter. + ParseVuNetMacParam(&'a str), + /// Failed parsing vhost-user-net sock parameter. + ParseVuNetSockParam, + /// Failed parsing vhost-user-net queue number parameter. + ParseVuNetNumQueuesParam(std::num::ParseIntError), + /// Failed parsing vhost-user-net queue size parameter. + ParseVuNetQueueSizeParam(std::num::ParseIntError), + /// Failed parsing vhost-user-net server parameter. + ParseVuNetServerParam(std::num::ParseIntError), } pub type Result<'a, T> = result::Result>; @@ -74,6 +87,7 @@ pub struct VmParams<'a> { pub serial: &'a str, pub console: &'a str, pub devices: Option>, + pub vhost_user_net: Option>, } fn parse_size(size: &str) -> Result { @@ -441,6 +455,64 @@ impl<'a> DeviceConfig<'a> { } } +pub struct VhostUserNetConfig<'a> { + pub mac: MacAddr, + pub vu_cfg: VhostUserConfig<'a>, +} + +impl<'a> VhostUserNetConfig<'a> { + pub fn parse(vhost_user_net: &'a str) -> Result { + // Split the parameters based on the comma delimiter + let params_list: Vec<&str> = vhost_user_net.split(',').collect(); + + let mut mac_str: &str = ""; + let mut sock: &str = ""; + let mut num_queues_str: &str = ""; + let mut queue_size_str: &str = ""; + + for param in params_list.iter() { + if param.starts_with("mac=") { + mac_str = ¶m[4..]; + } else if param.starts_with("sock=") { + sock = ¶m[5..]; + } else if param.starts_with("num_queues=") { + num_queues_str = ¶m[11..]; + } else if param.starts_with("queue_size=") { + queue_size_str = ¶m[11..]; + } + } + + let mut mac: MacAddr = MacAddr::local_random(); + let mut num_queues: usize = 2; + let mut queue_size: u16 = 256; + + if !mac_str.is_empty() { + mac = MacAddr::parse_str(mac_str).map_err(Error::ParseVuNetMacParam)?; + } + if sock.is_empty() { + return Err(Error::ParseVuNetSockParam); + } + if !num_queues_str.is_empty() { + num_queues = num_queues_str + .parse() + .map_err(Error::ParseVuNetNumQueuesParam)?; + } + if !queue_size_str.is_empty() { + queue_size = queue_size_str + .parse() + .map_err(Error::ParseVuNetQueueSizeParam)?; + } + + let vu_cfg = VhostUserConfig { + sock, + num_queues, + queue_size, + }; + + Ok(VhostUserNetConfig { mac, vu_cfg }) + } +} + pub struct VmConfig<'a> { pub cpus: CpusConfig, pub memory: MemoryConfig<'a>, @@ -454,6 +526,7 @@ pub struct VmConfig<'a> { pub serial: ConsoleConfig<'a>, pub console: ConsoleConfig<'a>, pub devices: Option>>, + pub vhost_user_net: Option>>, } impl<'a> VmConfig<'a> { @@ -509,6 +582,15 @@ impl<'a> VmConfig<'a> { devices = Some(device_config_list); } + let mut vhost_user_net: Option> = None; + if let Some(vhost_user_net_list) = &vm_params.vhost_user_net { + let mut vhost_user_net_config_list = Vec::new(); + for item in vhost_user_net_list.iter() { + vhost_user_net_config_list.push(VhostUserNetConfig::parse(item)?); + } + vhost_user_net = Some(vhost_user_net_config_list); + } + Ok(VmConfig { cpus: CpusConfig::parse(vm_params.cpus)?, memory: MemoryConfig::parse(vm_params.memory)?, @@ -522,6 +604,7 @@ impl<'a> VmConfig<'a> { serial, console, devices, + vhost_user_net, }) } } diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index f41dadf1b..4bb50e021 100755 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -234,6 +234,9 @@ pub enum DeviceManagerError { /// Cannot open disk path Disk(io::Error), + /// Cannot create vhost-user-net device + CreateVhostUserNet(vm_virtio::vhost_user::Error), + /// Cannot create virtio-blk device CreateVirtioBlock(io::Error), @@ -773,6 +776,15 @@ impl DeviceManager { &mut mem_slots, )?; + // Add virtio-vhost-user-net if required + DeviceManager::add_virtio_vhost_user_net_devices( + vm_info, + allocator, + pci, + buses, + &interrupt_info, + )?; + Ok(()) } @@ -1061,6 +1073,37 @@ impl DeviceManager { Ok(()) } + fn add_virtio_vhost_user_net_devices( + vm_info: &VmInfo, + allocator: &mut SystemAllocator, + pci: &mut PciConfigIo, + buses: &mut BusInfo, + interrupt_info: &InterruptInfo, + ) -> DeviceManagerResult<()> { + // Add vhost-user-net if required + if let Some(vhost_user_net_list_cfg) = &vm_info.vm_cfg.vhost_user_net { + for vhost_user_net_cfg in vhost_user_net_list_cfg.iter() { + let vhost_user_net_device = vm_virtio::vhost_user::Net::new( + vhost_user_net_cfg.mac, + vhost_user_net_cfg.vu_cfg, + ) + .map_err(DeviceManagerError::CreateVhostUserNet)?; + + DeviceManager::add_virtio_pci_device( + Box::new(vhost_user_net_device), + vm_info.memory, + allocator, + vm_info.vm_fd, + pci, + buses, + &interrupt_info, + )?; + } + } + + Ok(()) + } + fn create_kvm_device(vm: &Arc) -> DeviceManagerResult { let mut vfio_dev = kvm_bindings::kvm_create_device { type_: kvm_bindings::kvm_device_type_KVM_DEV_TYPE_VFIO,