1 // Copyright 2017 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! Network API wrappers for TAP interfaces. 6 //! # Slirp specific crate features 7 //! * **guest-to-host-net-loopback** - 8 //! Enables the guest to reach the host at a well known IP address on the 9 //! virtual network. 10 //! * **slirp** - 11 //! Enables the libslirp backend for virtio-net. 12 //! * **slirp-debug** - 13 //! Enables capture of all packets sent through libslirp in a pcap file. 14 //! * **slirp-ring-capture** - 15 //! Captures packets in a ring buffer and dumps them to a pcap file on exit. 16 17 pub mod sys; 18 use std::fmt; 19 use std::fmt::Display; 20 use std::io::Read; 21 use std::io::Write; 22 use std::net; 23 use std::num::ParseIntError; 24 use std::os::raw::*; 25 use std::str::FromStr; 26 27 use base::AsRawDescriptor; 28 use base::Error as SysError; 29 use base::RawDescriptor; 30 use remain::sorted; 31 use serde::Deserialize; 32 use serde::Deserializer; 33 use serde::Serialize; 34 use serde::Serializer; 35 pub use sys::TapT; 36 use thiserror::Error as ThisError; 37 38 #[cfg(all(feature = "slirp"))] 39 pub mod slirp; 40 #[cfg(all(feature = "slirp", windows))] 41 pub use slirp::Slirp; 42 43 #[sorted] 44 #[derive(ThisError, Debug)] 45 pub enum Error { 46 /// Unable to clone tap interface. 47 #[error("failed to clone tap interface: {0}")] 48 CloneTap(SysError), 49 /// Failed to create a socket. 50 #[error("failed to create a socket: {0}")] 51 CreateSocket(SysError), 52 /// Unable to create tap interface. 53 #[error("failed to create tap interface: {0}")] 54 CreateTap(SysError), 55 /// ioctl failed. 56 #[error("ioctl failed: {0}")] 57 IoctlError(SysError), 58 /// Couldn't open /dev/net/tun. 59 #[error("failed to open /dev/net/tun: {0}")] 60 OpenTun(SysError), 61 #[cfg(all(feature = "slirp", windows))] 62 #[error("slirp related error")] 63 Slirp(slirp::SlirpError), 64 } 65 66 pub type Result<T> = std::result::Result<T, Error>; 67 68 impl Error { sys_error(&self) -> SysError69 pub fn sys_error(&self) -> SysError { 70 match self { 71 Error::CreateSocket(e) => *e, 72 Error::OpenTun(e) => *e, 73 Error::CreateTap(e) => *e, 74 Error::CloneTap(e) => *e, 75 Error::IoctlError(e) => *e, 76 #[cfg(all(feature = "slirp", windows))] 77 Error::Slirp(e) => e.sys_error(), 78 } 79 } 80 } 81 82 #[sorted] 83 #[derive(ThisError, Debug, PartialEq, Eq)] 84 pub enum MacAddressError { 85 /// Invalid number of octets. 86 #[error("invalid number of octets: {0}")] 87 InvalidNumOctets(usize), 88 /// Failed to parse octet. 89 #[error("failed to parse octet: {0}")] 90 ParseOctet(ParseIntError), 91 } 92 93 /// An Ethernet mac address. This struct is compatible with the C `struct sockaddr`. 94 #[repr(C)] 95 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 96 pub struct MacAddress { 97 family: net_sys::sa_family_t, 98 addr: [u8; 6usize], 99 __pad: [u8; 8usize], 100 } 101 102 impl MacAddress { octets(&self) -> [u8; 6usize]103 pub fn octets(&self) -> [u8; 6usize] { 104 self.addr 105 } 106 } 107 108 impl FromStr for MacAddress { 109 type Err = MacAddressError; 110 from_str(s: &str) -> std::result::Result<Self, Self::Err>111 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 112 let octets: Vec<&str> = s.split(':').collect(); 113 if octets.len() != 6usize { 114 return Err(MacAddressError::InvalidNumOctets(octets.len())); 115 } 116 117 let mut result = MacAddress { 118 family: net_sys::ARPHRD_ETHER, 119 addr: [0; 6usize], 120 __pad: [0; 8usize], 121 }; 122 123 for (i, octet) in octets.iter().enumerate() { 124 result.addr[i] = u8::from_str_radix(octet, 16).map_err(MacAddressError::ParseOctet)?; 125 } 126 127 Ok(result) 128 } 129 } 130 131 impl Display for MacAddress { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 133 write!( 134 f, 135 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 136 self.addr[0], self.addr[1], self.addr[2], self.addr[3], self.addr[4], self.addr[5] 137 ) 138 } 139 } 140 141 impl<'de> Deserialize<'de> for MacAddress { deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> where D: Deserializer<'de>,142 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error> 143 where 144 D: Deserializer<'de>, 145 { 146 let s = String::deserialize(deserializer)?; 147 FromStr::from_str(&s).map_err(serde::de::Error::custom) 148 } 149 } 150 151 impl Serialize for MacAddress { serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,152 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> 153 where 154 S: Serializer, 155 { 156 serializer.collect_str(&self) 157 } 158 } 159 160 pub trait TapTCommon: Read + Write + AsRawDescriptor + Send + Sized { 161 /// Create a new tap interface named `name`, or open it if it already exists with the same 162 /// parameters. 163 /// 164 /// Set the `vnet_hdr` flag to true to allow offloading on this tap, which will add an extra 12 165 /// byte virtio net header to incoming frames. Offloading cannot be used if `vnet_hdr` is false. 166 /// Set 'multi_vq' to true, if tap have multi virt queue pairs new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result<Self>167 fn new_with_name(name: &[u8], vnet_hdr: bool, multi_vq: bool) -> Result<Self>; 168 169 /// Create a new tap interface. Set the `vnet_hdr` flag to true to allow offloading on this tap, 170 /// which will add an extra 12 byte virtio net header to incoming frames. Offloading cannot 171 /// be used if `vnet_hdr` is false. Set 'multi_vq' to true if tap has multi virt queue pairs. new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>172 fn new(vnet_hdr: bool, multi_vq: bool) -> Result<Self>; 173 174 /// Change the origin tap into multiqueue taps, this means create other taps based on the 175 /// origin tap. into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>176 fn into_mq_taps(self, vq_pairs: u16) -> Result<Vec<Self>>; 177 178 /// Get the host-side IP address for the tap interface. ip_addr(&self) -> Result<net::Ipv4Addr>179 fn ip_addr(&self) -> Result<net::Ipv4Addr>; 180 181 /// Set the host-side IP address for the tap interface. set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>182 fn set_ip_addr(&self, ip_addr: net::Ipv4Addr) -> Result<()>; 183 184 /// Get the netmask for the tap interface's subnet. netmask(&self) -> Result<net::Ipv4Addr>185 fn netmask(&self) -> Result<net::Ipv4Addr>; 186 187 /// Set the netmask for the subnet that the tap interface will exist on. set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>188 fn set_netmask(&self, netmask: net::Ipv4Addr) -> Result<()>; 189 190 /// Get the MTU for the tap interface. mtu(&self) -> Result<u16>191 fn mtu(&self) -> Result<u16>; 192 193 /// Set the MTU for the tap interface. set_mtu(&self, mtu: u16) -> Result<()>194 fn set_mtu(&self, mtu: u16) -> Result<()>; 195 196 /// Get the mac address for the tap interface. mac_address(&self) -> Result<MacAddress>197 fn mac_address(&self) -> Result<MacAddress>; 198 199 /// Set the mac address for the tap interface. set_mac_address(&self, mac_addr: MacAddress) -> Result<()>200 fn set_mac_address(&self, mac_addr: MacAddress) -> Result<()>; 201 202 /// Set the offload flags for the tap interface. set_offload(&self, flags: c_uint) -> Result<()>203 fn set_offload(&self, flags: c_uint) -> Result<()>; 204 205 /// Enable the tap interface. enable(&self) -> Result<()>206 fn enable(&self) -> Result<()>; 207 208 /// Set the size of the vnet hdr. set_vnet_hdr_size(&self, size: c_int) -> Result<()>209 fn set_vnet_hdr_size(&self, size: c_int) -> Result<()>; 210 get_ifreq(&self) -> net_sys::ifreq211 fn get_ifreq(&self) -> net_sys::ifreq; 212 213 /// Get the interface flags if_flags(&self) -> u32214 fn if_flags(&self) -> u32; 215 216 /// Try to clone try_clone(&self) -> Result<Self>217 fn try_clone(&self) -> Result<Self>; 218 219 /// Convert raw descriptor to from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>220 unsafe fn from_raw_descriptor(descriptor: RawDescriptor) -> Result<Self>; 221 } 222 223 #[cfg(test)] 224 mod tests { 225 use serde_json::*; 226 227 use super::*; 228 229 #[test] json_serialize_deserialize()230 fn json_serialize_deserialize() { 231 let mac_address = MacAddress { 232 family: net_sys::ARPHRD_ETHER, 233 addr: [0x3d, 0x70, 0xeb, 0x61, 0x1a, 0x91], 234 __pad: [0; 8usize], 235 }; 236 const SERIALIZED_ADDRESS: &str = "\"3D:70:EB:61:1A:91\""; 237 assert_eq!(to_string(&mac_address).unwrap(), SERIALIZED_ADDRESS); 238 assert_eq!( 239 from_str::<MacAddress>(SERIALIZED_ADDRESS).unwrap(), 240 mac_address 241 ); 242 } 243 } 244