diff --git a/net_util/src/tap.rs b/net_util/src/tap.rs index 7b9caad4c..d5eba0462 100644 --- a/net_util/src/tap.rs +++ b/net_util/src/tap.rs @@ -153,7 +153,7 @@ impl Tap { Self::open_named("vmtap%d", num_queue_pairs, None) } - pub fn from_tap_fd(fd: RawFd) -> Result { + pub fn from_tap_fd(fd: RawFd, num_queue_pairs: usize) -> Result { // Ensure that the file is opened non-blocking, this is particularly // needed when opened via the shell for macvtap. let ret = unsafe { @@ -181,6 +181,9 @@ impl Tap { let ifru_flags = ifreq.ifr_ifru.ifru_flags.as_mut(); *ifru_flags = (net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short; + if num_queue_pairs > 1 { + *ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short; + } } let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) }; if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST { @@ -591,7 +594,7 @@ mod tests { let orig_tap = Tap::new(1).unwrap(); let fd = orig_tap.as_raw_fd(); - let _new_tap = Tap::from_tap_fd(fd).unwrap(); + let _new_tap = Tap::from_tap_fd(fd, 1).unwrap(); } #[test] diff --git a/virtio-devices/src/net.rs b/virtio-devices/src/net.rs index 265a4e77f..56869af85 100644 --- a/virtio-devices/src/net.rs +++ b/virtio-devices/src/net.rs @@ -297,21 +297,28 @@ impl Net { ) } - pub fn from_tap_fd( + pub fn from_tap_fds( id: String, - fd: RawFd, + fds: &[RawFd], guest_mac: Option, iommu: bool, queue_size: u16, seccomp_action: SeccompAction, ) -> Result { - let tap = Tap::from_tap_fd(fd).map_err(Error::TapError)?; + let mut taps: Vec = Vec::new(); + let num_queue_pairs = fds.len(); + + for fd in fds.iter() { + let tap = Tap::from_tap_fd(*fd, num_queue_pairs).map_err(Error::TapError)?; + taps.push(tap); + } + Self::new_with_tap( id, - vec![tap], + taps, guest_mac, iommu, - 2, + num_queue_pairs * 2, queue_size, seccomp_action, ) diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 1ac3d749f..a3a7cf5a2 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -107,6 +107,8 @@ pub enum ValidationError { CpuTopologyZeroPart, /// Virtio needs a min of 2 queues VnetQueueLowerThan2, + /// The input queue number for virtio_net must match the number of input fds + VnetQueueFdMismatch, } type ValidationResult = std::result::Result; @@ -132,6 +134,10 @@ impl fmt::Display for ValidationError { "Product of CPU topology parts does not match maximum vCPUs" ), VnetQueueLowerThan2 => write!(f, "Number of queues to virtio_net less than 2"), + VnetQueueFdMismatch => write!( + f, + "Number of queues to virtio_net does not match the number of input FDs" + ), } } } @@ -765,7 +771,7 @@ pub struct NetConfig { #[serde(default)] pub id: Option, #[serde(default)] - pub fd: Option, + pub fds: Option>, } fn default_netconfig_tap() -> Option { @@ -806,14 +812,14 @@ impl Default for NetConfig { vhost_user: false, vhost_socket: None, id: None, - fd: None, + fds: None, } } } impl NetConfig { pub const SYNTAX: &'static str = "Network parameters \ - \"tap=,ip=,mask=,mac=,fd=,iommu=on|off,\ + \"tap=,ip=,mask=,mac=,fd=,iommu=on|off,\ num_queues=,queue_size=,\ vhost_user=,socket=,id=\""; @@ -869,7 +875,11 @@ impl NetConfig { .0; let vhost_socket = parser.get("socket"); let id = parser.get("id"); - let fd = parser.convert("fd").map_err(Error::ParseNetwork)?; + let fds = parser + .convert::("fd") + .map_err(Error::ParseNetwork)? + .map(|v| v.0.iter().map(|e| *e as i32).collect()); + let config = NetConfig { tap, ip, @@ -882,7 +892,7 @@ impl NetConfig { vhost_user, vhost_socket, id, - fd, + fds, }; config.validate().map_err(Error::Validation)?; Ok(config) @@ -891,6 +901,11 @@ impl NetConfig { if self.num_queues < 2 { return Err(ValidationError::VnetQueueLowerThan2); } + + if self.fds.is_some() && self.fds.as_ref().unwrap().len() * 2 != self.num_queues { + return Err(ValidationError::VnetQueueFdMismatch); + } + Ok(()) } } @@ -1949,10 +1964,11 @@ mod tests { ); assert_eq!( - NetConfig::parse("mac=de:ad:be:ef:12:34,fd=3")?, + NetConfig::parse("mac=de:ad:be:ef:12:34,fd=3:7,num_queues=4")?, NetConfig { mac: MacAddr::parse_str("de:ad:be:ef:12:34").unwrap(), - fd: Some(3), + fds: Some(vec![3, 7]), + num_queues: 4, ..Default::default() } ); diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index d151332b6..664d70dd8 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -1790,11 +1790,11 @@ impl DeviceManager { ) .map_err(DeviceManagerError::CreateVirtioNet)?, )) - } else if let Some(fd) = net_cfg.fd { + } else if let Some(fds) = &net_cfg.fds { Arc::new(Mutex::new( - virtio_devices::Net::from_tap_fd( + virtio_devices::Net::from_tap_fds( id.clone(), - fd, + fds, Some(net_cfg.mac), net_cfg.iommu, net_cfg.queue_size,