mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-23 00:11:16 +00:00
net_util: Add API for creating a Tap from an fd
Ultimately this will allow the creation of a virtio-net device that is backed by a file descriptor. This function ensures that the TAP device is correctly setup with offloading and non-blocking. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
16c2eebfd1
commit
385d734847
@ -5,7 +5,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the THIRD-PARTY file.
|
// found in the THIRD-PARTY file.
|
||||||
|
|
||||||
use super::{create_sockaddr, create_socket, Error as NetUtilError, MacAddr};
|
use super::{create_sockaddr, create_socket, vnet_hdr_len, Error as NetUtilError, MacAddr};
|
||||||
use mac::MAC_ADDR_LEN;
|
use mac::MAC_ADDR_LEN;
|
||||||
use net_gen;
|
use net_gen;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@ -153,6 +153,50 @@ impl Tap {
|
|||||||
Self::open_named("vmtap%d", num_queue_pairs, None)
|
Self::open_named("vmtap%d", num_queue_pairs, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_tap_fd(fd: RawFd) -> Result<Tap> {
|
||||||
|
// Ensure that the file is opened non-blocking, this is particularly
|
||||||
|
// needed when opened via the shell for macvtap.
|
||||||
|
let ret = unsafe {
|
||||||
|
let mut flags = libc::fcntl(fd, libc::F_GETFL);
|
||||||
|
flags |= libc::O_NONBLOCK;
|
||||||
|
libc::fcntl(fd, libc::F_SETFL, flags)
|
||||||
|
};
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::ConfigureTap(IoError::last_os_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tap_file = unsafe { File::from_raw_fd(fd) };
|
||||||
|
let mut ifreq: net_gen::ifreq = Default::default();
|
||||||
|
|
||||||
|
// Get current config including name
|
||||||
|
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq) };
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::IoctlError(IoError::last_os_error()));
|
||||||
|
}
|
||||||
|
let if_name = unsafe { *ifreq.ifr_ifrn.ifrn_name.as_ref() }.to_vec();
|
||||||
|
|
||||||
|
// Try and update flags. Depending on how the tap was created (macvtap
|
||||||
|
// or via open_named()) this might return -EEXIST so we just ignore that.
|
||||||
|
unsafe {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
return Err(Error::ConfigureTap(IoError::last_os_error()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tap = Tap { if_name, tap_file };
|
||||||
|
let offload_flags =
|
||||||
|
net_gen::TUN_F_CSUM | net_gen::TUN_F_UFO | net_gen::TUN_F_TSO4 | net_gen::TUN_F_TSO6;
|
||||||
|
let vnet_hdr_size = vnet_hdr_len() as i32;
|
||||||
|
tap.set_offload(offload_flags)?;
|
||||||
|
tap.set_vnet_hdr_size(vnet_hdr_size)?;
|
||||||
|
|
||||||
|
Ok(tap)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the host-side IP address for the tap interface.
|
/// Set the host-side IP address for the tap interface.
|
||||||
pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
|
pub fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()> {
|
||||||
let sock = create_socket().map_err(Error::NetUtil)?;
|
let sock = create_socket().map_err(Error::NetUtil)?;
|
||||||
@ -539,6 +583,13 @@ mod tests {
|
|||||||
println!("created tap: {:?}", t);
|
println!("created tap: {:?}", t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_tap_from_fd() {
|
||||||
|
let orig_tap = Tap::new(1).unwrap();
|
||||||
|
let fd = orig_tap.as_raw_fd();
|
||||||
|
let _new_tap = Tap::from_tap_fd(fd).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tap_configure() {
|
fn test_tap_configure() {
|
||||||
// This should be the first thing to be called inside the function, so everything else
|
// This should be the first thing to be called inside the function, so everything else
|
||||||
|
Loading…
Reference in New Issue
Block a user