• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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