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