vmm/devices/virtio/net/
persist.rs1use std::io;
7use std::sync::{Arc, Mutex};
8
9use serde::{Deserialize, Serialize};
10
11use super::device::{Net, RxBuffers};
12use super::{NET_NUM_QUEUES, NET_QUEUE_MAX_SIZE, RX_INDEX, TapError};
13use crate::devices::virtio::device::{ActiveState, DeviceState};
14use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_NET;
15use crate::devices::virtio::persist::{PersistError as VirtioStateError, VirtioDeviceState};
16use crate::devices::virtio::transport::VirtioInterrupt;
17use crate::mmds::data_store::Mmds;
18use crate::mmds::ns::MmdsNetworkStack;
19use crate::mmds::persist::MmdsNetworkStackState;
20use crate::rate_limiter::RateLimiter;
21use crate::rate_limiter::persist::RateLimiterState;
22use crate::snapshot::Persist;
23use crate::utils::net::mac::MacAddr;
24use crate::vstate::memory::GuestMemoryMmap;
25
26#[derive(Debug, Default, Clone, Serialize, Deserialize)]
29pub struct NetConfigSpaceState {
30 guest_mac: Option<MacAddr>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct NetState {
37 pub id: String,
38 pub tap_if_name: String,
39 rx_rate_limiter_state: RateLimiterState,
40 tx_rate_limiter_state: RateLimiterState,
41 pub mmds_ns: Option<MmdsNetworkStackState>,
43 config_space: NetConfigSpaceState,
44 pub virtio_state: VirtioDeviceState,
45}
46
47#[derive(Debug)]
49pub struct NetConstructorArgs {
50 pub mem: GuestMemoryMmap,
52 pub mmds: Option<Arc<Mutex<Mmds>>>,
54}
55
56#[derive(Debug, thiserror::Error, displaydoc::Display)]
58pub enum NetPersistError {
59 CreateNet(#[from] super::NetError),
61 CreateRateLimiter(#[from] io::Error),
63 VirtioState(#[from] VirtioStateError),
65 NoMmdsDataStore,
67 TapSetOffload(TapError),
69}
70
71impl Persist<'_> for Net {
72 type State = NetState;
73 type ConstructorArgs = NetConstructorArgs;
74 type Error = NetPersistError;
75
76 fn save(&self) -> Self::State {
77 NetState {
78 id: self.id().clone(),
79 tap_if_name: self.iface_name(),
80 rx_rate_limiter_state: self.rx_rate_limiter.save(),
81 tx_rate_limiter_state: self.tx_rate_limiter.save(),
82 mmds_ns: self.mmds_ns.as_ref().map(|mmds| mmds.save()),
83 config_space: NetConfigSpaceState {
84 guest_mac: self.guest_mac,
85 },
86 virtio_state: VirtioDeviceState::from_device(self),
87 }
88 }
89
90 fn restore(
91 constructor_args: Self::ConstructorArgs,
92 state: &Self::State,
93 ) -> Result<Self, Self::Error> {
94 let rx_rate_limiter = RateLimiter::restore((), &state.rx_rate_limiter_state)?;
96 let tx_rate_limiter = RateLimiter::restore((), &state.tx_rate_limiter_state)?;
97 let mut net = Net::new(
98 state.id.clone(),
99 &state.tap_if_name,
100 state.config_space.guest_mac,
101 rx_rate_limiter,
102 tx_rate_limiter,
103 )?;
104
105 if let Some(mmds_ns) = &state.mmds_ns {
109 net.mmds_ns = Some(
112 MmdsNetworkStack::restore(
113 constructor_args
114 .mmds
115 .map_or_else(|| Err(NetPersistError::NoMmdsDataStore), Ok)?,
116 mmds_ns,
117 )
118 .unwrap(),
119 );
120 }
121
122 net.queues = state.virtio_state.build_queues_checked(
123 &constructor_args.mem,
124 VIRTIO_ID_NET,
125 NET_NUM_QUEUES,
126 NET_QUEUE_MAX_SIZE,
127 )?;
128 net.avail_features = state.virtio_state.avail_features;
129 net.acked_features = state.virtio_state.acked_features;
130
131 Ok(net)
132 }
133}
134
135#[cfg(test)]
136mod tests {
137
138 use super::*;
139 use crate::devices::virtio::device::VirtioDevice;
140 use crate::devices::virtio::net::test_utils::{default_net, default_net_no_mmds};
141 use crate::devices::virtio::test_utils::{default_interrupt, default_mem};
142 use crate::snapshot::Snapshot;
143
144 fn validate_save_and_restore(net: Net, mmds_ds: Option<Arc<Mutex<Mmds>>>) {
145 let guest_mem = default_mem();
146 let mut mem = vec![0; 4096];
147
148 let id;
149 let tap_if_name;
150 let has_mmds_ns;
151 let allow_mmds_requests;
152 let virtio_state;
153
154 {
156 Snapshot::new(net.save())
157 .save(&mut mem.as_mut_slice())
158 .unwrap();
159
160 id = net.id.clone();
162 tap_if_name = net.iface_name();
163 has_mmds_ns = net.mmds_ns.is_some();
164 allow_mmds_requests = has_mmds_ns && mmds_ds.is_some();
165 virtio_state = VirtioDeviceState::from_device(&net);
166 }
167
168 drop(net);
171 {
172 match Net::restore(
174 NetConstructorArgs {
175 mem: guest_mem,
176 mmds: mmds_ds,
177 },
178 &Snapshot::load_without_crc_check(mem.as_slice())
179 .unwrap()
180 .data,
181 ) {
182 Ok(restored_net) => {
183 assert_eq!(restored_net.device_type(), VIRTIO_ID_NET);
185 assert_eq!(restored_net.avail_features(), virtio_state.avail_features);
186 assert_eq!(restored_net.acked_features(), virtio_state.acked_features);
187 assert_eq!(restored_net.is_activated(), virtio_state.activated);
188
189 assert_eq!(&restored_net.id, &id);
191 assert_eq!(&restored_net.iface_name(), &tap_if_name);
192 assert_eq!(restored_net.mmds_ns.is_some(), allow_mmds_requests);
193 assert_eq!(restored_net.rx_rate_limiter, RateLimiter::default());
194 assert_eq!(restored_net.tx_rate_limiter, RateLimiter::default());
195 }
196 Err(NetPersistError::NoMmdsDataStore) => {
197 assert!(has_mmds_ns && !allow_mmds_requests)
198 }
199 _ => unreachable!(),
200 }
201 }
202 }
203
204 #[test]
205 fn test_persistence() {
206 let mmds = Some(Arc::new(Mutex::new(Mmds::default())));
207 validate_save_and_restore(default_net(), mmds.as_ref().cloned());
208 validate_save_and_restore(default_net_no_mmds(), None);
209
210 validate_save_and_restore(default_net_no_mmds(), mmds);
214
215 validate_save_and_restore(default_net(), None);
218 }
219}