1use std::convert::TryInto;
5use std::ops::Deref;
6use std::sync::{Arc, Mutex};
7
8use serde::{Deserialize, Serialize};
9
10use super::RateLimiterConfig;
11use crate::VmmError;
12use crate::devices::virtio::net::{Net, TapError};
13use crate::utils::net::mac::MacAddr;
14
15#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
18#[serde(deny_unknown_fields)]
19pub struct NetworkInterfaceConfig {
20 pub iface_id: String,
22 pub host_dev_name: String,
24 pub guest_mac: Option<MacAddr>,
26 pub rx_rate_limiter: Option<RateLimiterConfig>,
28 pub tx_rate_limiter: Option<RateLimiterConfig>,
30}
31
32impl From<&Net> for NetworkInterfaceConfig {
33 fn from(net: &Net) -> Self {
34 let rx_rl: RateLimiterConfig = net.rx_rate_limiter().into();
35 let tx_rl: RateLimiterConfig = net.tx_rate_limiter().into();
36 NetworkInterfaceConfig {
37 iface_id: net.id().clone(),
38 host_dev_name: net.iface_name(),
39 guest_mac: net.guest_mac().copied(),
40 rx_rate_limiter: rx_rl.into_option(),
41 tx_rate_limiter: tx_rl.into_option(),
42 }
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
49#[serde(deny_unknown_fields)]
50pub struct NetworkInterfaceUpdateConfig {
51 pub iface_id: String,
53 pub rx_rate_limiter: Option<RateLimiterConfig>,
56 pub tx_rate_limiter: Option<RateLimiterConfig>,
59}
60
61#[derive(Debug, thiserror::Error, displaydoc::Display)]
63pub enum NetworkInterfaceError {
64 CreateNetworkDevice(#[from] crate::devices::virtio::net::NetError),
66 CreateRateLimiter(#[from] std::io::Error),
68 DeviceUpdate(#[from] VmmError),
70 GuestMacAddressInUse(String),
72 OpenTap(#[from] TapError),
74}
75
76#[derive(Debug, Default)]
78pub struct NetBuilder {
79 net_devices: Vec<Arc<Mutex<Net>>>,
80}
81
82impl NetBuilder {
83 pub fn new() -> Self {
85 NetBuilder {
86 net_devices: Vec::new(),
88 }
89 }
90
91 pub fn iter(&self) -> ::std::slice::Iter<'_, Arc<Mutex<Net>>> {
93 self.net_devices.iter()
94 }
95
96 pub fn add_device(&mut self, device: Arc<Mutex<Net>>) {
98 self.net_devices.push(device);
99 }
100
101 pub fn build(
104 &mut self,
105 netif_config: NetworkInterfaceConfig,
106 ) -> Result<Arc<Mutex<Net>>, NetworkInterfaceError> {
107 if let Some(ref mac_address) = netif_config.guest_mac {
108 let mac_conflict = |net: &Arc<Mutex<Net>>| {
109 let net = net.lock().expect("Poisoned lock");
110 Some(mac_address) == net.guest_mac() && &netif_config.iface_id != net.id()
112 };
113 if self.net_devices.iter().any(mac_conflict) {
117 return Err(NetworkInterfaceError::GuestMacAddressInUse(
118 mac_address.to_string(),
119 ));
120 }
121 }
122
123 if let Some(index) = self
125 .net_devices
126 .iter()
127 .position(|net| net.lock().expect("Poisoned lock").id() == &netif_config.iface_id)
128 {
129 self.net_devices.swap_remove(index);
130 }
131
132 let net = Arc::new(Mutex::new(Self::create_net(netif_config)?));
134 self.net_devices.push(net.clone());
135
136 Ok(net)
137 }
138
139 pub fn create_net(cfg: NetworkInterfaceConfig) -> Result<Net, NetworkInterfaceError> {
141 let rx_rate_limiter = cfg
142 .rx_rate_limiter
143 .map(super::RateLimiterConfig::try_into)
144 .transpose()
145 .map_err(NetworkInterfaceError::CreateRateLimiter)?;
146 let tx_rate_limiter = cfg
147 .tx_rate_limiter
148 .map(super::RateLimiterConfig::try_into)
149 .transpose()
150 .map_err(NetworkInterfaceError::CreateRateLimiter)?;
151
152 crate::devices::virtio::net::Net::new(
154 cfg.iface_id,
155 &cfg.host_dev_name,
156 cfg.guest_mac,
157 rx_rate_limiter.unwrap_or_default(),
158 tx_rate_limiter.unwrap_or_default(),
159 )
160 .map_err(NetworkInterfaceError::CreateNetworkDevice)
161 }
162
163 pub fn configs(&self) -> Vec<NetworkInterfaceConfig> {
165 let mut ret = vec![];
166 for net in &self.net_devices {
167 ret.push(NetworkInterfaceConfig::from(net.lock().unwrap().deref()));
168 }
169 ret
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use std::str::FromStr;
176
177 use super::*;
178 use crate::rate_limiter::RateLimiter;
179
180 impl NetBuilder {
181 pub(crate) fn len(&self) -> usize {
182 self.net_devices.len()
183 }
184 }
185
186 fn create_netif(id: &str, name: &str, mac: &str) -> NetworkInterfaceConfig {
187 NetworkInterfaceConfig {
188 iface_id: String::from(id),
189 host_dev_name: String::from(name),
190 guest_mac: Some(MacAddr::from_str(mac).unwrap()),
191 rx_rate_limiter: RateLimiterConfig::default().into_option(),
192 tx_rate_limiter: RateLimiterConfig::default().into_option(),
193 }
194 }
195
196 impl Clone for NetworkInterfaceConfig {
197 fn clone(&self) -> Self {
198 NetworkInterfaceConfig {
199 iface_id: self.iface_id.clone(),
200 host_dev_name: self.host_dev_name.clone(),
201 guest_mac: self.guest_mac,
202 rx_rate_limiter: None,
203 tx_rate_limiter: None,
204 }
205 }
206 }
207
208 #[test]
209 fn test_insert() {
210 let mut net_builder = NetBuilder::new();
211
212 let id_1 = "id_1";
213 let mut host_dev_name_1 = "dev1";
214 let mut guest_mac_1 = "01:23:45:67:89:0a";
215
216 let netif_1 = create_netif(id_1, host_dev_name_1, guest_mac_1);
218 net_builder.build(netif_1).unwrap();
219 assert_eq!(net_builder.net_devices.len(), 1);
220
221 guest_mac_1 = "01:23:45:67:89:0b";
223 let netif_1 = create_netif(id_1, host_dev_name_1, guest_mac_1);
224
225 net_builder.build(netif_1).unwrap();
226 assert_eq!(net_builder.net_devices.len(), 1);
227
228 host_dev_name_1 = "dev2";
230 let netif_1 = create_netif(id_1, host_dev_name_1, guest_mac_1);
231 net_builder.build(netif_1).unwrap();
232 assert_eq!(net_builder.net_devices.len(), 1);
233 }
234
235 #[test]
236 fn test_insert_error_cases() {
237 let mut net_builder = NetBuilder::new();
238
239 let id_1 = "id_1";
240 let host_dev_name_1 = "dev3";
241 let guest_mac_1 = "01:23:45:67:89:0a";
242
243 let netif_1 = create_netif(id_1, host_dev_name_1, guest_mac_1);
245 net_builder.build(netif_1).unwrap();
246
247 let id_2 = "id_2";
250 let host_dev_name_2 = "dev4";
251 let guest_mac_2 = "01:23:45:67:89:0b";
252
253 let netif_2 = create_netif(id_2, host_dev_name_2, guest_mac_1);
254 let expected_error = NetworkInterfaceError::GuestMacAddressInUse(guest_mac_1.into());
255 assert_eq!(
256 net_builder.build(netif_2).err().unwrap().to_string(),
257 expected_error.to_string()
258 );
259 assert_eq!(net_builder.net_devices.len(), 1);
260
261 let netif_2 = create_netif(id_2, host_dev_name_1, guest_mac_2);
263 assert_eq!(
264 net_builder.build(netif_2).err().unwrap().to_string(),
265 NetworkInterfaceError::CreateNetworkDevice(
266 crate::devices::virtio::net::NetError::TapOpen(TapError::IfreqExecuteError(
267 std::io::Error::from_raw_os_error(16),
268 host_dev_name_1.to_string()
269 ))
270 )
271 .to_string()
272 );
273 assert_eq!(net_builder.net_devices.len(), 1);
274
275 let netif_2 = create_netif(id_2, host_dev_name_2, guest_mac_2);
277 net_builder.build(netif_2).unwrap();
278
279 let netif_2 = create_netif(id_2, host_dev_name_2, guest_mac_1);
282 let expected_error = NetworkInterfaceError::GuestMacAddressInUse(guest_mac_1.into());
283 assert_eq!(
284 net_builder.build(netif_2).err().unwrap().to_string(),
285 expected_error.to_string()
286 );
287
288 let netif_2 = create_netif(id_2, host_dev_name_1, guest_mac_2);
290 assert_eq!(
291 net_builder.build(netif_2).err().unwrap().to_string(),
292 NetworkInterfaceError::CreateNetworkDevice(
293 crate::devices::virtio::net::NetError::TapOpen(TapError::IfreqExecuteError(
294 std::io::Error::from_raw_os_error(16),
295 host_dev_name_1.to_string()
296 ))
297 )
298 .to_string()
299 );
300 }
301
302 #[test]
303 fn test_net_config() {
304 let net_id = "id";
305 let host_dev_name = "dev";
306 let guest_mac = "01:23:45:67:89:0b";
307
308 let net_if_cfg = create_netif(net_id, host_dev_name, guest_mac);
309 assert_eq!(
310 net_if_cfg.guest_mac.unwrap(),
311 MacAddr::from_str(guest_mac).unwrap()
312 );
313
314 let mut net_builder = NetBuilder::new();
315 net_builder.build(net_if_cfg.clone()).unwrap();
316 assert_eq!(net_builder.net_devices.len(), 1);
317
318 let configs = net_builder.configs();
319 assert_eq!(configs.len(), 1);
320 assert_eq!(configs.first().unwrap(), &net_if_cfg);
321 }
322
323 #[test]
324 fn test_add_device() {
325 let mut net_builder = NetBuilder::new();
326 let net_id = "test_id";
327 let host_dev_name = "dev";
328 let guest_mac = "01:23:45:67:89:0b";
329
330 let net = Net::new(
331 net_id.to_string(),
332 host_dev_name,
333 Some(MacAddr::from_str(guest_mac).unwrap()),
334 RateLimiter::default(),
335 RateLimiter::default(),
336 )
337 .unwrap();
338
339 net_builder.add_device(Arc::new(Mutex::new(net)));
340 assert_eq!(net_builder.net_devices.len(), 1);
341 assert_eq!(
342 net_builder
343 .net_devices
344 .pop()
345 .unwrap()
346 .lock()
347 .unwrap()
348 .deref()
349 .id(),
350 net_id
351 );
352 }
353}