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