mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
net_gen: replace net_gen with libc
The libc crate provides all functionality provided by the net_gen crate. Removing the net_gen crate reduces the maintenance burden. The switch to libc required some fixes, most notably the switch from a `Vec<u8>` to a `CString` for the `net_util::Tap.if_name` field. On-behalf-of: SAP julian.schindel@sap.com Signed-off-by: Julian Schindel <julian.schindel@cyberus-technology.de>
This commit is contained in:
committed by
Rob Bradford
parent
3a56f20ee1
commit
2b28c5b15a
@@ -59,15 +59,15 @@ unsafe impl ByteValued for VirtioNetConfig {}
|
||||
|
||||
/// Create a sockaddr_in from an IPv4 address, and expose it as
|
||||
/// an opaque sockaddr suitable for usage by socket ioctls.
|
||||
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> net_gen::sockaddr {
|
||||
// IPv4 addresses big-endian (network order), but Ipv4Addr will give us
|
||||
// a view of those bytes directly so we can avoid any endian trickiness.
|
||||
let addr_in = net_gen::sockaddr_in {
|
||||
sin_family: net_gen::AF_INET as u16,
|
||||
fn create_sockaddr(ip_addr: net::Ipv4Addr) -> libc::sockaddr {
|
||||
let addr_in = libc::sockaddr_in {
|
||||
sin_family: libc::AF_INET as u16,
|
||||
sin_port: 0,
|
||||
// SAFETY: ip_addr can be safely transmute to in_addr
|
||||
sin_addr: unsafe { mem::transmute::<[u8; 4], net_gen::inn::in_addr>(ip_addr.octets()) },
|
||||
__pad: [0; 8usize],
|
||||
sin_addr: libc::in_addr {
|
||||
// Use network byte order (big endian).
|
||||
s_addr: ip_addr.to_bits().to_be(),
|
||||
},
|
||||
sin_zero: [0; 8],
|
||||
};
|
||||
|
||||
// SAFETY: addr_in can be safely transmute to sockaddr
|
||||
@@ -167,19 +167,19 @@ pub fn build_net_config_space_with_mq(
|
||||
pub fn virtio_features_to_tap_offload(features: u64) -> c_uint {
|
||||
let mut tap_offloads: c_uint = 0;
|
||||
if features & (1 << VIRTIO_NET_F_GUEST_CSUM) != 0 {
|
||||
tap_offloads |= net_gen::TUN_F_CSUM;
|
||||
tap_offloads |= libc::TUN_F_CSUM;
|
||||
}
|
||||
if features & (1 << VIRTIO_NET_F_GUEST_TSO4) != 0 {
|
||||
tap_offloads |= net_gen::TUN_F_TSO4;
|
||||
tap_offloads |= libc::TUN_F_TSO4;
|
||||
}
|
||||
if features & (1 << VIRTIO_NET_F_GUEST_TSO6) != 0 {
|
||||
tap_offloads |= net_gen::TUN_F_TSO6;
|
||||
tap_offloads |= libc::TUN_F_TSO6;
|
||||
}
|
||||
if features & (1 << VIRTIO_NET_F_GUEST_ECN) != 0 {
|
||||
tap_offloads |= net_gen::TUN_F_TSO_ECN;
|
||||
tap_offloads |= libc::TUN_F_TSO_ECN;
|
||||
}
|
||||
if features & (1 << VIRTIO_NET_F_GUEST_UFO) != 0 {
|
||||
tap_offloads |= net_gen::TUN_F_UFO;
|
||||
tap_offloads |= libc::TUN_F_UFO;
|
||||
}
|
||||
|
||||
tap_offloads
|
||||
@@ -194,7 +194,7 @@ mod unit_tests {
|
||||
let addr: net::Ipv4Addr = "10.0.0.1".parse().unwrap();
|
||||
let sockaddr = create_sockaddr(addr);
|
||||
|
||||
assert_eq!(sockaddr.sa_family, net_gen::AF_INET as u16);
|
||||
assert_eq!(sockaddr.sa_family, libc::AF_INET as u16);
|
||||
|
||||
let data = &sockaddr.sa_data[..];
|
||||
|
||||
|
||||
@@ -48,11 +48,11 @@ fn check_mq_support(if_name: &Option<&str>, queue_pairs: usize) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
let tun_flags_str = fs::read_to_string(path).map_err(Error::ReadSysfsTunFlags)?;
|
||||
let tun_flags = u32::from_str_radix(tun_flags_str.trim().trim_start_matches("0x"), 16)
|
||||
let tun_flags = i32::from_str_radix(tun_flags_str.trim().trim_start_matches("0x"), 16)
|
||||
.map_err(Error::ConvertHexStringToInt)?;
|
||||
if (tun_flags & net_gen::IFF_MULTI_QUEUE != 0) && !mq {
|
||||
if (tun_flags & libc::IFF_MULTI_QUEUE != 0) && !mq {
|
||||
return Err(Error::MultiQueueNoDeviceSupport);
|
||||
} else if (tun_flags & net_gen::IFF_MULTI_QUEUE == 0) && mq {
|
||||
} else if (tun_flags & libc::IFF_MULTI_QUEUE == 0) && mq {
|
||||
return Err(Error::MultiQueueNoTapSupport);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the THIRD-PARTY file.
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs::File;
|
||||
use std::io::{Error as IoError, Read, Result as IoResult, Write};
|
||||
use std::net::{IpAddr, Ipv6Addr};
|
||||
use std::os::raw::*;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
use libc::{__c_anonymous_ifr_ifru, ifreq};
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val};
|
||||
|
||||
@@ -43,6 +45,8 @@ pub enum Error {
|
||||
NetUtil(#[source] NetUtilError),
|
||||
#[error("Interface name too long (max length is {MAX_INTERFACE_NAME_LEN}): {0}")]
|
||||
IfnameTooLong(String),
|
||||
#[error("Interface name contains interior NUL byte: {0:?}")]
|
||||
IfnameContainsNUL(String),
|
||||
#[error("Invalid interface name (does it exist?): {0}")]
|
||||
InvalidIfname(String),
|
||||
#[error("Error parsing MAC data")]
|
||||
@@ -62,7 +66,8 @@ pub type Result<T> = ::std::result::Result<T, Error>;
|
||||
#[derive(Debug)]
|
||||
pub struct Tap {
|
||||
tap_file: File,
|
||||
if_name: Vec<u8>,
|
||||
/// The name does not exceed [`MAX_INTERFACE_NAME_LEN`] bytes excluding the NUL byte.
|
||||
if_name: CString,
|
||||
}
|
||||
|
||||
impl PartialEq for Tap {
|
||||
@@ -80,23 +85,6 @@ impl std::clone::Clone for Tap {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a byte vector representing the contents of a null terminated C string which
|
||||
// contains if_name.
|
||||
fn build_terminated_if_name(if_name: &str) -> Result<Vec<u8>> {
|
||||
// Convert the string slice to bytes, and shadow the variable,
|
||||
// since we no longer need the &str version.
|
||||
let bytes = if_name.as_bytes();
|
||||
|
||||
if bytes.len() > MAX_INTERFACE_NAME_LEN {
|
||||
return Err(Error::IfnameTooLong(if_name.to_string()));
|
||||
}
|
||||
|
||||
let mut terminated_if_name = vec![b'\0'; bytes.len() + 1];
|
||||
terminated_if_name[..bytes.len()].copy_from_slice(bytes);
|
||||
|
||||
Ok(terminated_if_name)
|
||||
}
|
||||
|
||||
fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8> {
|
||||
let mask = mask.segments();
|
||||
let mut iter = mask.iter();
|
||||
@@ -169,7 +157,12 @@ impl Tap {
|
||||
}
|
||||
|
||||
pub fn open_named(if_name: &str, num_queue_pairs: usize, flags: Option<i32>) -> Result<Tap> {
|
||||
let terminated_if_name = build_terminated_if_name(if_name)?;
|
||||
if if_name.len() > MAX_INTERFACE_NAME_LEN {
|
||||
return Err(Error::IfnameTooLong(if_name.to_string()));
|
||||
}
|
||||
|
||||
let terminated_if_name =
|
||||
CString::new(if_name).map_err(|_| Error::IfnameContainsNUL(if_name.to_string()))?;
|
||||
|
||||
// SAFETY: FFI call
|
||||
let fd = unsafe {
|
||||
@@ -192,42 +185,48 @@ impl Tap {
|
||||
// value.
|
||||
let mut features = 0;
|
||||
// SAFETY: IOCTL with correct arguments
|
||||
let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNGETFEATURES(), &mut features) };
|
||||
let ret =
|
||||
unsafe { ioctl_with_mut_ref(&tuntap, libc::TUNGETFEATURES as c_ulong, &mut features) };
|
||||
if ret < 0 {
|
||||
return Err(Error::GetFeatures(IoError::last_os_error()));
|
||||
}
|
||||
|
||||
// Check if the user parameters match the kernel support for MQ
|
||||
if (features & net_gen::IFF_MULTI_QUEUE == 0) && num_queue_pairs > 1 {
|
||||
if (features & libc::IFF_MULTI_QUEUE == 0) && num_queue_pairs > 1 {
|
||||
return Err(Error::MultiQueueKernelSupport);
|
||||
}
|
||||
|
||||
// This is pretty messy because of the unions used by ifreq. Since we
|
||||
// don't call as_mut on the same union field more than once, this block
|
||||
// is safe.
|
||||
let mut ifreq: net_gen::ifreq = Default::default();
|
||||
// SAFETY: see the comment above.
|
||||
unsafe {
|
||||
let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
|
||||
let name_slice = &mut ifrn_name[..terminated_if_name.len()];
|
||||
name_slice.copy_from_slice(terminated_if_name.as_slice());
|
||||
ifreq.ifr_ifru.ifru_flags =
|
||||
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
|
||||
if num_queue_pairs > 1 {
|
||||
ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
|
||||
}
|
||||
let mut ifru_flags = (libc::IFF_TAP | libc::IFF_NO_PI | libc::IFF_VNET_HDR) as c_short;
|
||||
if num_queue_pairs > 1 {
|
||||
ifru_flags |= libc::IFF_MULTI_QUEUE as c_short;
|
||||
}
|
||||
|
||||
let mut ifreq = libc::ifreq {
|
||||
ifr_name: [0; libc::IFNAMSIZ],
|
||||
ifr_ifru: __c_anonymous_ifr_ifru { ifru_flags },
|
||||
};
|
||||
|
||||
// Convert and copy bytes to `ifr_name` buffer.
|
||||
// `terminated_if_name` will fit into `ifr_name` since we enforce the length limit
|
||||
// above.
|
||||
ifreq
|
||||
.ifr_name
|
||||
.iter_mut()
|
||||
.zip(terminated_if_name.as_bytes_with_nul())
|
||||
.for_each(|(ifr_name_char, terminated_if_name_byte)| {
|
||||
*ifr_name_char = *terminated_if_name_byte as c_char;
|
||||
});
|
||||
|
||||
// SAFETY: ioctl is safe since we call it with a valid tap fd and check the return
|
||||
// value.
|
||||
let ret = unsafe { ioctl_with_mut_ref(&tuntap, net_gen::TUNSETIFF(), &mut ifreq) };
|
||||
let ret = unsafe { ioctl_with_mut_ref(&tuntap, libc::TUNSETIFF as c_ulong, &mut ifreq) };
|
||||
if ret < 0 {
|
||||
return Err(Error::ConfigureTap(IoError::last_os_error()));
|
||||
}
|
||||
|
||||
// SAFETY: only the name is accessed, and it's cloned out.
|
||||
let mut if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
|
||||
if_name.truncate(terminated_if_name.len() - 1);
|
||||
// SAFETY: `ifreq.ifr_name` is set by the `ioctl_with_mut_ref` call and we checked the
|
||||
// return code, so the name must be a valid `CStr`.
|
||||
let if_name = unsafe { CStr::from_ptr(ifreq.ifr_name.as_ptr()) }.to_owned();
|
||||
Ok(Tap {
|
||||
tap_file: tuntap,
|
||||
if_name,
|
||||
@@ -254,27 +253,36 @@ impl Tap {
|
||||
|
||||
// SAFETY: fd is a tap fd
|
||||
let tap_file = unsafe { File::from_raw_fd(fd) };
|
||||
let mut ifreq: net_gen::ifreq = Default::default();
|
||||
let mut ifreq: libc::ifreq = ifreq {
|
||||
ifr_name: [0; libc::IFNAMSIZ],
|
||||
ifr_ifru: __c_anonymous_ifr_ifru { ifru_flags: 0 },
|
||||
};
|
||||
|
||||
// Get current config including name
|
||||
// SAFETY: IOCTL with correct arguments
|
||||
unsafe { Self::ioctl_with_mut_ref(&tap_file, net_gen::TUNGETIFF(), &mut ifreq)? };
|
||||
unsafe { Self::ioctl_with_mut_ref(&tap_file, libc::TUNGETIFF as c_ulong, &mut ifreq)? };
|
||||
|
||||
// SAFETY: We only access one field of the ifru union
|
||||
let if_name = unsafe { ifreq.ifr_ifrn.ifrn_name }.to_vec();
|
||||
let if_name = {
|
||||
let ifr_ptr = ifreq.ifr_name.as_ptr();
|
||||
// SAFETY: The `ifr_name` field of the union is a valid, nul-terminated C string since it
|
||||
// was just set by the ioctl call, and we checked for errors.
|
||||
// We immediately convert the `CStr` to the owned `CString, so the memory of the union field
|
||||
// is not accessed or mutated during the lifetime of the `Cstr`.
|
||||
unsafe { CStr::from_ptr(ifr_ptr).to_owned() }
|
||||
};
|
||||
|
||||
// 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.
|
||||
// SAFETY: access union fields
|
||||
unsafe {
|
||||
ifreq.ifr_ifru.ifru_flags =
|
||||
(net_gen::IFF_TAP | net_gen::IFF_NO_PI | net_gen::IFF_VNET_HDR) as c_short;
|
||||
(libc::IFF_TAP | libc::IFF_NO_PI | libc::IFF_VNET_HDR) as c_short;
|
||||
if num_queue_pairs > 1 {
|
||||
ifreq.ifr_ifru.ifru_flags |= net_gen::IFF_MULTI_QUEUE as c_short;
|
||||
ifreq.ifr_ifru.ifru_flags |= libc::IFF_MULTI_QUEUE as c_short;
|
||||
}
|
||||
}
|
||||
// SAFETY: IOCTL with correct arguments
|
||||
let ret = unsafe { ioctl_with_mut_ref(&tap_file, net_gen::TUNSETIFF(), &mut ifreq) };
|
||||
let ret = unsafe { ioctl_with_mut_ref(&tap_file, libc::TUNSETIFF as c_ulong, &mut ifreq) };
|
||||
if ret < 0 && IoError::last_os_error().raw_os_error().unwrap() != libc::EEXIST {
|
||||
return Err(Error::ConfigureTap(IoError::last_os_error()));
|
||||
}
|
||||
@@ -300,7 +308,7 @@ impl Tap {
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe {
|
||||
Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq)?;
|
||||
Self::ioctl_with_ref(&sock, libc::SIOCSIFADDR as c_ulong, &ifreq)?;
|
||||
}
|
||||
|
||||
if let Some(IpAddr::V4(mask)) = netmask {
|
||||
@@ -308,11 +316,7 @@ impl Tap {
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe {
|
||||
Self::ioctl_with_ref(
|
||||
&sock,
|
||||
net_gen::sockios::SIOCSIFNETMASK as c_ulong,
|
||||
&ifreq,
|
||||
)?;
|
||||
Self::ioctl_with_ref(&sock, libc::SIOCSIFNETMASK as c_ulong, &ifreq)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,18 +326,14 @@ impl Tap {
|
||||
let ifindex = {
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe {
|
||||
Self::ioctl_with_ref(
|
||||
&sock,
|
||||
net_gen::sockios::SIOCGIFINDEX as c_ulong,
|
||||
&ifreq,
|
||||
)?;
|
||||
Self::ioctl_with_ref(&sock, libc::SIOCGIFINDEX as c_ulong, &ifreq)?;
|
||||
}
|
||||
|
||||
// SAFETY: ifru_ivalue contains the ifindex and is set by the previous ioctl
|
||||
unsafe {
|
||||
match ifreq.ifr_ifru.ifru_ivalue {
|
||||
match ifreq.ifr_ifru.ifru_ifindex {
|
||||
0 => {
|
||||
let name = String::from_utf8_lossy(&self.if_name).to_string();
|
||||
let name = self.if_name.to_string_lossy().to_string();
|
||||
return Err(Error::InvalidIfname(name));
|
||||
}
|
||||
i => i,
|
||||
@@ -347,19 +347,17 @@ impl Tap {
|
||||
None => 0,
|
||||
};
|
||||
|
||||
let ifreq = net_gen::in6_ifreq {
|
||||
let ifreq = libc::in6_ifreq {
|
||||
// SAFETY: addr can be safely transmuted to in6_addr
|
||||
ifr6_addr: unsafe {
|
||||
std::mem::transmute::<[u8; 16], net_gen::ipv6::in6_addr>(addr.octets())
|
||||
std::mem::transmute::<[u8; 16], libc::in6_addr>(addr.octets())
|
||||
},
|
||||
ifr6_prefixlen: prefixlen as u32,
|
||||
ifr6_ifindex: ifindex,
|
||||
};
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe {
|
||||
Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFADDR as c_ulong, &ifreq)
|
||||
}
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCSIFADDR as c_ulong, &ifreq) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -380,18 +378,18 @@ impl Tap {
|
||||
let mut ifreq = self.get_ifreq();
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? };
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCGIFHWADDR as c_ulong, &ifreq)? };
|
||||
|
||||
// SAFETY: We only access one field of the ifru union
|
||||
unsafe {
|
||||
let ifru_hwaddr = &mut ifreq.ifr_ifru.ifru_hwaddr;
|
||||
for (i, v) in addr.get_bytes().iter().enumerate() {
|
||||
ifru_hwaddr.sa_data[i] = *v as c_uchar;
|
||||
ifru_hwaddr.sa_data[i] = *v as c_char;
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFHWADDR as c_ulong, &ifreq) }
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCSIFHWADDR as c_ulong, &ifreq) }
|
||||
}
|
||||
|
||||
/// Get mac addr for tap interface.
|
||||
@@ -401,12 +399,21 @@ impl Tap {
|
||||
let ifreq = self.get_ifreq();
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFHWADDR as c_ulong, &ifreq)? };
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCGIFHWADDR as c_ulong, &ifreq)? };
|
||||
|
||||
// SAFETY: We only access one field of the ifru union
|
||||
let addr = unsafe {
|
||||
MacAddr::from_bytes(&ifreq.ifr_ifru.ifru_hwaddr.sa_data[0..MAC_ADDR_LEN])
|
||||
.map_err(Error::MacParsing)?
|
||||
let addr = {
|
||||
let bytes: Vec<u8> =
|
||||
// SAFETY: The `ioctl_with_ref` ensures accessing `ifru_hwaddr` is valid.
|
||||
unsafe { ifreq.ifr_ifru.ifru_hwaddr.sa_data[0..MAC_ADDR_LEN].iter() }
|
||||
.map(|byte| {
|
||||
// On some architectures, `c_char` is already a `u8`.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
{
|
||||
*byte as u8
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
MacAddr::from_bytes(&bytes).map_err(Error::MacParsing)?
|
||||
};
|
||||
Ok(addr)
|
||||
}
|
||||
@@ -418,7 +425,7 @@ impl Tap {
|
||||
let ifreq = self.get_ifreq();
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFMTU as c_ulong, &ifreq)? };
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCGIFMTU as c_ulong, &ifreq)? };
|
||||
|
||||
// SAFETY: access a union field
|
||||
let mtu = unsafe { ifreq.ifr_ifru.ifru_mtu };
|
||||
@@ -439,13 +446,19 @@ impl Tap {
|
||||
ifreq.ifr_ifru.ifru_mtu = mtu;
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFMTU as c_ulong, &ifreq) }
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCSIFMTU as c_ulong, &ifreq) }
|
||||
}
|
||||
|
||||
/// Set the offload flags for the tap interface.
|
||||
pub fn set_offload(&self, flags: c_uint) -> Result<()> {
|
||||
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_val(&self.tap_file, net_gen::TUNSETOFFLOAD(), flags as c_ulong) }
|
||||
unsafe {
|
||||
Self::ioctl_with_val(
|
||||
&self.tap_file,
|
||||
libc::TUNSETOFFLOAD as c_ulong,
|
||||
flags as c_ulong,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable the tap interface.
|
||||
@@ -455,50 +468,46 @@ impl Tap {
|
||||
let mut ifreq = self.get_ifreq();
|
||||
|
||||
// SAFETY: IOCTL with correct arguments
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCGIFFLAGS as c_ulong, &ifreq)? };
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCGIFFLAGS as c_ulong, &ifreq)? };
|
||||
|
||||
// If TAP device is already up don't try and enable it
|
||||
// SAFETY: access a union field
|
||||
let ifru_flags = unsafe { ifreq.ifr_ifru.ifru_flags };
|
||||
if ifru_flags & net_gen::net_device_flags_IFF_UP as i16
|
||||
== net_gen::net_device_flags_IFF_UP as i16
|
||||
{
|
||||
if ifru_flags & libc::IFF_UP as i16 == libc::IFF_UP as i16 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
ifreq.ifr_ifru.ifru_flags = net_gen::net_device_flags_IFF_UP as i16;
|
||||
ifreq.ifr_ifru.ifru_flags = libc::IFF_UP as i16;
|
||||
|
||||
// SAFETY: ioctl is safe. Called with a valid sock fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&sock, net_gen::sockios::SIOCSIFFLAGS as c_ulong, &ifreq) }
|
||||
unsafe { Self::ioctl_with_ref(&sock, libc::SIOCSIFFLAGS as c_ulong, &ifreq) }
|
||||
}
|
||||
|
||||
/// Set the size of the vnet hdr.
|
||||
pub fn set_vnet_hdr_size(&self, size: c_int) -> Result<()> {
|
||||
// SAFETY: ioctl is safe. Called with a valid tap fd, and we check the return.
|
||||
unsafe { Self::ioctl_with_ref(&self.tap_file, net_gen::TUNSETVNETHDRSZ(), &size) }
|
||||
unsafe { Self::ioctl_with_ref(&self.tap_file, libc::TUNSETVNETHDRSZ as c_ulong, &size) }
|
||||
}
|
||||
|
||||
fn get_ifreq(&self) -> net_gen::ifreq {
|
||||
let mut ifreq: net_gen::ifreq = Default::default();
|
||||
fn get_ifreq(&self) -> libc::ifreq {
|
||||
let mut ifreq: libc::ifreq = libc::ifreq {
|
||||
ifr_name: [0; libc::IFNAMSIZ],
|
||||
ifr_ifru: __c_anonymous_ifr_ifru { ifru_flags: 0 },
|
||||
};
|
||||
|
||||
// This sets the name of the interface, which is the only entry
|
||||
// in a single-field union.
|
||||
// SAFETY: access union fields and we're sure the copy is okay.
|
||||
unsafe {
|
||||
let ifrn_name = ifreq.ifr_ifrn.ifrn_name.as_mut();
|
||||
let name_slice = &mut ifrn_name[..self.if_name.len()];
|
||||
name_slice.copy_from_slice(&self.if_name);
|
||||
}
|
||||
// Convert and copy bytes to `ifr_name` buffer.
|
||||
// `self.if_name` will fit into `ifr_name` since we enforce the length when setting it.
|
||||
ifreq
|
||||
.ifr_name
|
||||
.iter_mut()
|
||||
.zip(self.if_name.as_bytes_with_nul())
|
||||
.for_each(|(ifr_name_char, terminated_if_name_byte)| {
|
||||
*ifr_name_char = *terminated_if_name_byte as c_char;
|
||||
});
|
||||
|
||||
ifreq
|
||||
}
|
||||
|
||||
/// Returns the raw bytes of the interface name, which may or may not be
|
||||
/// valid UTF-8.
|
||||
pub fn if_name_as_bytes(&self) -> &[u8] {
|
||||
&self.if_name
|
||||
}
|
||||
|
||||
/// Returns the interface name as a string, truncated at the first NUL byte
|
||||
/// if present.
|
||||
///
|
||||
@@ -509,19 +518,20 @@ impl Tap {
|
||||
/// thus valid UTF-8. Also, self-generated interface names form CHV are
|
||||
/// also always created from Rust strings, thus valid UTF-8.
|
||||
pub fn if_name_as_str(&self) -> &str {
|
||||
// All bytes until first NUL.
|
||||
let nul_terminated = self
|
||||
.if_name_as_bytes()
|
||||
.split(|&b| b == 0)
|
||||
.next()
|
||||
.unwrap_or(&[]);
|
||||
|
||||
// Panicking here is fine, see function documentation.
|
||||
std::str::from_utf8(nul_terminated).expect("Tap interface name should be valid UTF-8")
|
||||
std::str::from_utf8(self.if_name.as_bytes())
|
||||
.expect("Tap interface name should be valid UTF-8")
|
||||
}
|
||||
|
||||
#[cfg(fuzzing)]
|
||||
pub fn new_for_fuzzing(tap_file: File, if_name: Vec<u8>) -> Self {
|
||||
pub fn new_for_fuzzing(tap_file: File, if_name: &str) -> Self {
|
||||
if if_name.len() > MAX_INTERFACE_NAME_LEN {
|
||||
panic!("provided name longer than `MAX_INTERFACE_NAME_LEN`")
|
||||
}
|
||||
|
||||
let if_name = CString::new(if_name)
|
||||
.map_err(|_| Error::IfnameContainsNUL(if_name.to_string()))
|
||||
.unwrap();
|
||||
Tap { tap_file, if_name }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user