You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
7.3 KiB

// Copyright 2017 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Network API wrappers for TAP interfaces.
//! # Slirp specific crate features
//! * **guest-to-host-net-loopback** -
//! Enables the guest to reach the host at a well known IP address on the
//! virtual network.
//! * **slirp** -
//! Enables the libslirp backend for virtio-net.
//! * **slirp-debug** -
//! Enables capture of all packets sent through libslirp in a pcap file.
//! * **slirp-ring-capture** -
//! Captures packets in a ring buffer and dumps them to a pcap file on exit.
pub mod sys;
use std::fmt;
use std::fmt::Display;
use std::io::Read;
use std::io::Write;
use std::net;
use std::num::ParseIntError;
use std::os::raw::*;
use std::str::FromStr;
use base::AsRawDescriptor;
use base::Error as SysError;
use base::RawDescriptor;
use remain::sorted;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
pub use sys::TapT;
use thiserror::Error as ThisError;
#[cfg(all(feature = "slirp"))]
pub mod slirp;
#[cfg(all(feature = "slirp", windows))]
pub use slirp::Slirp;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
/// Unable to clone tap interface.
#[error("failed to clone tap interface: {0}")]
CloneTap(SysError),
/// Failed to create a socket.
#[error("failed to create a socket: {0}")]
CreateSocket(SysError),
/// Unable to create tap interface.
#[error("failed to create tap interface: {0}")]
CreateTap(SysError),
/// ioctl failed.
#[error("ioctl failed: {0}")]
IoctlError(SysError),
/// Couldn't open /dev/net/tun.
#[error("failed to open /dev/net/tun: {0}")]
OpenTun(SysError),
#[cfg(all(feature = "slirp", windows))]
#[error("slirp related error")]
Slirp(slirp::SlirpError),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub fn sys_error(&self) -> SysError {
match self {
Error::CreateSocket(e) => *e,
Error::OpenTun(e) => *e,
Error::CreateTap(e) => *e,
Error::CloneTap(e) => *e,
Error::IoctlError(e) => *e,
#[cfg(all(feature = "slirp", windows))]
Error::Slirp(e) => e.sys_error(),
}
}
}
#[sorted]
#[derive(ThisError, Debug, PartialEq, Eq)]
pub enum MacAddressError {
/// Invalid number of octets.
#[error("invalid number of octets: {0}")]
InvalidNumOctets(usize),
/// Failed to parse octet.
#[error("failed to parse octet: {0}")]
ParseOctet(ParseIntError),
}
/// An Ethernet mac address. This struct is compatible with the C `struct sockaddr`.
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct MacAddress {
family: net_sys::sa_family_t,
addr: [u8; 6usize],
__pad: [u8; 8usize],
}
impl MacAddress {
pub fn octets(&self) -> [u8; 6usize] {
self.addr
}
}
impl FromStr for MacAddress {
type Err = MacAddressError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let octets: Vec<&str> = s.split(':').collect();
if octets.len() != 6usize {
return Err(MacAddressError::InvalidNumOctets(octets.len()));
}
let mut result = MacAddress {
family: net_sys::ARPHRD_ETHER,
addr: [0; 6usize],
__pad: [0; 8usize],
};
for (i, octet) in octets.iter().enumerate() {
result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?;
}
Ok(result)
}
}
impl Display for MacAddress {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5]
)
}
}
impl<'de> Deserialize<'de> for MacAddress {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
impl Serialize for MacAddress {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.collect_str(&self)
}
}
pub trait TapTCommon: Read + Write + AsRawDescriptor + Send + Sized {
/// Create a new tap interface named `name`, or open it if it already exists with the same
/// parameters.
///
/// Set the `vnet_hdr` flag to true to allow offloading on this tap, which will add an extra 12
/// byte virtio net header to incoming frames. Offloading cannot be used if `vnet_hdr` is false.
/// Set 'multi_vq' to true, if tap have multi virt queue pairs
fn new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
/// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap,
/// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot
/// be used if `vnet_hdr` is false. Set 'multi_vq' to true if tap has multi virt queue pairs.
fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>;
/// Change the origin tap into multiqueue taps, this means create other taps based on the
/// origin tap.
fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>;
/// Get the host-side IP address for the tap interface.
fn ip_addr(&self) -> Result<net::Ipv4Addr>;
/// Set the host-side IP address for the tap interface.
fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>;
/// Get the netmask for the tap interface's subnet.
fn netmask(&self) -> Result<net::Ipv4Addr>;
/// Set the netmask for the subnet that the tap interface will exist on.
fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>;
/// Get the MTU for the tap interface.
fn mtu(&self) -> Result<u16>;
/// Set the MTU for the tap interface.
fn set_mtu(&self, mtu: u16) -> Result<()>;
/// Get the mac address for the tap interface.
fn mac_address(&self) -> Result<MacAddress>;
/// Set the mac address for the tap interface.
fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>;
/// Set the offload flags for the tap interface.
fn set_offload(&self, flags: c_uint) -> Result<()>;
/// Enable the tap interface.
fn enable(&self) -> Result<()>;
/// Set the size of the vnet hdr.
fn set_vnet_hdr_size(&self, size: c_int) -> Result<()>;
fn get_ifreq(&self) -> net_sys::ifreq;
/// Get the interface flags
fn if_flags(&self) -> u32;
/// Try to clone
fn try_clone(&self) -> Result<Self>;
/// Convert raw descriptor to
unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>;
}
#[cfg(test)]
mod tests {
use serde_json::*;
use super::*;
#[test]
fn json_serialize_deserialize() {
let mac_address = MacAddress {
family: net_sys::ARPHRD_ETHER,
addr: [0x3d, 0x70, 0xeb, 0x61, 0x1a, 0x91],
__pad: [0; 8usize],
};
const SERIALIZED_ADDRESS: &str = "\"3D:70:EB:61:1A:91\"";
assert_eq!(to_string(&mac_address).unwrap(), SERIALIZED_ADDRESS);
assert_eq!(
from_str::<MacAddress>(SERIALIZED_ADDRESS).unwrap(),
mac_address
);
}
}