net_util: Add multiple queue support for tap

Add support to allow VMMs to open the same tap device many times, it will
create multiple file descriptors meanwhile.

Signed-off-by: Cathy Zhang <cathy.zhang@intel.com>
This commit is contained in:
Cathy Zhang
2020-01-10 00:03:24 +08:00
committed by Sebastien Boeuf
parent cf7e0cdf95
commit 4ab88a8173
3 changed files with 28 additions and 17 deletions
+26 -15
View File
@@ -40,7 +40,7 @@ pub type Result<T> = ::std::result::Result<T, Error>;
#[derive(Debug)] #[derive(Debug)]
pub struct Tap { pub struct Tap {
tap_file: File, tap_file: File,
if_name: [u8; 16usize], if_name: Vec<u8>,
} }
impl PartialEq for Tap { impl PartialEq for Tap {
@@ -53,7 +53,7 @@ impl std::clone::Clone for Tap {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Tap { Tap {
tap_file: self.tap_file.try_clone().unwrap(), tap_file: self.tap_file.try_clone().unwrap(),
if_name: self.if_name, if_name: self.if_name.clone(),
} }
} }
} }
@@ -78,7 +78,7 @@ fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
} }
impl Tap { impl Tap {
pub fn open_named(if_name: &str) -> Result<Tap> { pub fn open_named(if_name: &str, num_queue_pairs: usize) -> Result<Tap> {
let terminated_if_name = build_terminated_if_name(if_name)?; let terminated_if_name = build_terminated_if_name(if_name)?;
let fd = unsafe { let fd = unsafe {
@@ -107,6 +107,9 @@ impl Tap {
name_slice.copy_from_slice(terminated_if_name.as_slice()); name_slice.copy_from_slice(terminated_if_name.as_slice());
*ifru_flags = *ifru_flags =
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short; (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;
}
} }
// ioctl is safe since we call it with a valid tap fd and check the return // ioctl is safe since we call it with a valid tap fd and check the return
@@ -117,16 +120,19 @@ impl Tap {
return Err(Error::CreateTap(IoError::last_os_error())); return Err(Error::CreateTap(IoError::last_os_error()));
} }
let if_name_temp = unsafe { *ifreq.ifr_ifrn.ifrn_name.as_ref() };
let mut if_name = if_name_temp.to_vec();
if_name.truncate(terminated_if_name.len() - 1);
// Safe since only the name is accessed, and it's cloned out. // Safe since only the name is accessed, and it's cloned out.
Ok(Tap { Ok(Tap {
tap_file: tuntap, tap_file: tuntap,
if_name: unsafe { *ifreq.ifr_ifrn.ifrn_name.as_ref() }, if_name,
}) })
} }
/// Create a new tap interface. /// Create a new tap interface.
pub fn new() -> Result<Tap> { pub fn new(num_queue_pairs: usize) -> Result<Tap> {
Self::open_named("vmtap%d") Self::open_named("vmtap%d", num_queue_pairs)
} }
/// Set the host-side IP address for the tap interface. /// Set the host-side IP address for the tap interface.
@@ -232,11 +238,16 @@ impl Tap {
// in a single-field union. // in a single-field union.
unsafe { unsafe {
let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut(); let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
ifrn_name.clone_from_slice(&self.if_name); let name_slice = &mut ifrn_name[..self.if_name.len()];
name_slice.copy_from_slice(&self.if_name);
} }
ifreq ifreq
} }
pub fn get_if_name(&self) -> Vec<u8> {
self.if_name.clone()
}
} }
impl Read for Tap { impl Read for Tap {
@@ -423,7 +434,7 @@ mod tests {
#[test] #[test]
fn test_tap_create() { fn test_tap_create() {
let t = Tap::new().unwrap(); let t = Tap::new(1).unwrap();
println!("created tap: {:?}", t); println!("created tap: {:?}", t);
} }
@@ -435,7 +446,7 @@ mod tests {
// the end of the function. // the end of the function.
let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
let tap = Tap::new().unwrap(); let tap = Tap::new(1).unwrap();
let ip_addr: net::Ipv4Addr = (*tap_ip_guard).parse().unwrap(); let ip_addr: net::Ipv4Addr = (*tap_ip_guard).parse().unwrap();
let netmask: net::Ipv4Addr = SUBNET_MASK.parse().unwrap(); let netmask: net::Ipv4Addr = SUBNET_MASK.parse().unwrap();
@@ -448,21 +459,21 @@ mod tests {
#[test] #[test]
fn test_set_options() { fn test_set_options() {
// This line will fail to provide an initialized FD if the test is not run as root. // This line will fail to provide an initialized FD if the test is not run as root.
let tap = Tap::new().unwrap(); let tap = Tap::new(1).unwrap();
tap.set_vnet_hdr_size(16).unwrap(); tap.set_vnet_hdr_size(16).unwrap();
tap.set_offload(0).unwrap(); tap.set_offload(0).unwrap();
} }
#[test] #[test]
fn test_tap_enable() { fn test_tap_enable() {
let tap = Tap::new().unwrap(); let tap = Tap::new(1).unwrap();
let ret = tap.enable(); let ret = tap.enable();
assert!(ret.is_ok()); assert!(ret.is_ok());
} }
#[test] #[test]
fn test_tap_get_ifreq() { fn test_tap_get_ifreq() {
let tap = Tap::new().unwrap(); let tap = Tap::new(1).unwrap();
let ret = tap.get_ifreq(); let ret = tap.get_ifreq();
assert_eq!( assert_eq!(
"__BindgenUnionField", "__BindgenUnionField",
@@ -472,7 +483,7 @@ mod tests {
#[test] #[test]
fn test_raw_fd() { fn test_raw_fd() {
let tap = Tap::new().unwrap(); let tap = Tap::new(1).unwrap();
assert_eq!(tap.as_raw_fd(), tap.tap_file.as_raw_fd()); assert_eq!(tap.as_raw_fd(), tap.tap_file.as_raw_fd());
} }
@@ -480,7 +491,7 @@ mod tests {
fn test_read() { fn test_read() {
let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
let mut tap = Tap::new().unwrap(); let mut tap = Tap::new(1).unwrap();
tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap(); tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap();
tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap(); tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap();
tap.enable().unwrap(); tap.enable().unwrap();
@@ -541,7 +552,7 @@ mod tests {
fn test_write() { fn test_write() {
let tap_ip_guard = TAP_IP_LOCK.lock().unwrap(); let tap_ip_guard = TAP_IP_LOCK.lock().unwrap();
let mut tap = Tap::new().unwrap(); let mut tap = Tap::new(1).unwrap();
tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap(); tap.set_ip_addr((*tap_ip_guard).parse().unwrap()).unwrap();
tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap(); tap.set_netmask(SUBNET_MASK.parse().unwrap()).unwrap();
tap.enable().unwrap(); tap.enable().unwrap();
+1 -1
View File
@@ -427,7 +427,7 @@ pub fn open_tap(ip_addr: Ipv4Addr, netmask: Ipv4Addr) -> Result<Tap> {
let vnet_hdr_size = vnet_hdr_len() as i32; let vnet_hdr_size = vnet_hdr_len() as i32;
let flag = net_gen::TUN_F_CSUM | net_gen::TUN_F_UFO | net_gen::TUN_F_TSO4 | net_gen::TUN_F_TSO6; let flag = net_gen::TUN_F_CSUM | net_gen::TUN_F_UFO | net_gen::TUN_F_TSO4 | net_gen::TUN_F_TSO6;
let tap = Tap::new().map_err(Error::TapOpen)?; let tap = Tap::new(1).map_err(Error::TapOpen)?;
tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?; tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?;
tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?; tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?;
tap.enable().map_err(Error::TapEnable)?; tap.enable().map_err(Error::TapEnable)?;
+1 -1
View File
@@ -991,7 +991,7 @@ impl DeviceManager {
if let Some(net_list_cfg) = &vm_info.vm_cfg.lock().unwrap().net { if let Some(net_list_cfg) = &vm_info.vm_cfg.lock().unwrap().net {
for net_cfg in net_list_cfg.iter() { for net_cfg in net_list_cfg.iter() {
let virtio_net_device = if let Some(ref tap_if_name) = net_cfg.tap { let virtio_net_device = if let Some(ref tap_if_name) = net_cfg.tap {
let tap = Tap::open_named(tap_if_name).map_err(DeviceManagerError::OpenTap)?; let tap = Tap::open_named(tap_if_name, 1).map_err(DeviceManagerError::OpenTap)?;
Arc::new(Mutex::new( Arc::new(Mutex::new(
vm_virtio::Net::new_with_tap(tap, Some(net_cfg.mac), net_cfg.iommu) vm_virtio::Net::new_with_tap(tap, Some(net_cfg.mac), net_cfg.iommu)
.map_err(DeviceManagerError::CreateVirtioNet)?, .map_err(DeviceManagerError::CreateVirtioNet)?,