1use std::collections::BTreeMap;
6use std::mem;
7use std::path::Path;
8
9use anyhow::anyhow;
10use anyhow::Context;
11use base::error;
12use base::warn;
13use base::AsRawDescriptor;
14use base::RawDescriptor;
15use base::Tube;
16use base::WorkerThread;
17use net_util::MacAddress;
18use net_util::TapT;
19use vhost::NetT as VhostNetT;
20use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
21use virtio_sys::virtio_net;
22use vm_memory::GuestMemory;
23use zerocopy::IntoBytes;
24
25use super::control_socket::*;
26use super::worker::Worker;
27use super::Error;
28use super::Result;
29use crate::pci::MsixStatus;
30use crate::virtio::copy_config;
31use crate::virtio::net::build_config;
32use crate::virtio::DeviceType;
33use crate::virtio::Interrupt;
34use crate::virtio::Queue;
35use crate::virtio::VirtioDevice;
36use crate::PciAddress;
37
38const QUEUE_SIZE: u16 = 256;
39const NUM_QUEUES: usize = 2;
40const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
41
42pub struct Net<T: TapT + 'static, U: VhostNetT<T> + 'static> {
43 worker_thread: Option<WorkerThread<(Worker<U>, T)>>,
44 tap: Option<T>,
45 guest_mac: Option<[u8; 6]>,
46 vhost_net_handle: Option<U>,
47 avail_features: u64,
48 acked_features: u64,
49 worker_client_tube: Tube,
50 worker_server_tube: Option<Tube>,
51 pci_address: Option<PciAddress>,
52}
53
54impl<T, U> Net<T, U>
55where
56 T: TapT,
57 U: VhostNetT<T>,
58{
59 pub fn new(
62 vhost_net_device_path: &Path,
63 base_features: u64,
64 tap: T,
65 mac_addr: Option<MacAddress>,
66 use_packed_queue: bool,
67 pci_address: Option<PciAddress>,
68 mrg_rxbuf: bool,
69 ) -> Result<Net<T, U>> {
70 tap.set_offload(
72 net_sys::TUN_F_CSUM | net_sys::TUN_F_UFO | net_sys::TUN_F_TSO4 | net_sys::TUN_F_TSO6,
73 )
74 .map_err(Error::TapSetOffload)?;
75
76 let vnet_hdr_size = mem::size_of::<virtio_net::virtio_net_hdr_mrg_rxbuf>();
78 tap.set_vnet_hdr_size(vnet_hdr_size)
79 .map_err(Error::TapSetVnetHdrSize)?;
80
81 let vhost_net_handle = U::new(vhost_net_device_path).map_err(Error::VhostOpen)?;
82
83 let mut avail_features = base_features
84 | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
85 | 1 << virtio_net::VIRTIO_NET_F_CSUM
86 | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
87 | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
88 | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
89 | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
90 | 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF;
91
92 if use_packed_queue {
93 avail_features |= 1 << VIRTIO_F_RING_PACKED;
94 }
95
96 if mac_addr.is_some() {
97 avail_features |= 1 << virtio_net::VIRTIO_NET_F_MAC;
98 }
99
100 if mrg_rxbuf {
101 avail_features |= 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF;
102 }
103
104 let (worker_client_tube, worker_server_tube) = Tube::pair().map_err(Error::CreateTube)?;
105
106 Ok(Net {
107 worker_thread: None,
108 tap: Some(tap),
109 guest_mac: mac_addr.map(|mac| mac.octets()),
110 vhost_net_handle: Some(vhost_net_handle),
111 avail_features,
112 acked_features: 0u64,
113 worker_client_tube,
114 worker_server_tube: Some(worker_server_tube),
115 pci_address,
116 })
117 }
118}
119
120impl<T, U> VirtioDevice for Net<T, U>
121where
122 T: TapT + 'static,
123 U: VhostNetT<T> + 'static,
124{
125 fn keep_rds(&self) -> Vec<RawDescriptor> {
126 let mut keep_rds = Vec::new();
127
128 if let Some(tap) = &self.tap {
129 keep_rds.push(tap.as_raw_descriptor());
130 }
131
132 if let Some(vhost_net_handle) = &self.vhost_net_handle {
133 keep_rds.push(vhost_net_handle.as_raw_descriptor());
134 }
135
136 keep_rds.push(self.worker_client_tube.as_raw_descriptor());
137
138 if let Some(worker_server_tube) = &self.worker_server_tube {
139 keep_rds.push(worker_server_tube.as_raw_descriptor());
140 }
141
142 keep_rds
143 }
144
145 fn device_type(&self) -> DeviceType {
146 DeviceType::Net
147 }
148
149 fn queue_max_sizes(&self) -> &[u16] {
150 QUEUE_SIZES
151 }
152
153 fn features(&self) -> u64 {
154 self.avail_features
155 }
156
157 fn ack_features(&mut self, value: u64) {
158 let mut v = value;
159
160 let unrequested_features = v & !self.avail_features;
162 if unrequested_features != 0 {
163 warn!("net: virtio net got unknown feature ack: {:x}", v);
164
165 v &= !unrequested_features;
167 }
168 self.acked_features |= v;
169 }
170
171 fn read_config(&self, offset: u64, data: &mut [u8]) {
172 let vq_pairs = QUEUE_SIZES.len() / 2;
173 let config_space = build_config(vq_pairs as u16, 0, self.guest_mac);
175 copy_config(data, 0, config_space.as_bytes(), offset);
176 }
177
178 fn activate(
179 &mut self,
180 mem: GuestMemory,
181 interrupt: Interrupt,
182 queues: BTreeMap<usize, Queue>,
183 ) -> anyhow::Result<()> {
184 if queues.len() != NUM_QUEUES {
185 return Err(anyhow!(
186 "net: expected {} queues, got {}",
187 NUM_QUEUES,
188 queues.len()
189 ));
190 }
191
192 let vhost_net_handle = self
193 .vhost_net_handle
194 .take()
195 .context("missing vhost_net_handle")?;
196 let tap = self.tap.take().context("missing tap")?;
197 let acked_features = self.acked_features;
198 let mut worker = Worker::new(
199 "vhost-net",
200 queues,
201 vhost_net_handle,
202 interrupt,
203 acked_features,
204 self.worker_server_tube
205 .take()
206 .expect("worker control tube missing"),
207 mem,
208 None,
209 )
210 .context("net worker init exited with error")?;
211 for idx in 0..NUM_QUEUES {
212 worker
213 .vhost_handle
214 .set_backend(idx, Some(&tap))
215 .map_err(Error::VhostNetSetBackend)?;
216 }
217 self.worker_thread = Some(WorkerThread::start("vhost_net", move |kill_evt| {
218 let result = worker.run(kill_evt);
219 if let Err(e) = result {
220 error!("net worker thread exited with error: {}", e);
221 }
222 for idx in 0..NUM_QUEUES {
223 if let Err(e) = worker.vhost_handle.set_backend(idx, None) {
224 error!("net worker thread failed to clear backend: {:#}", e);
225 }
226 }
227 (worker, tap)
228 }));
229
230 Ok(())
231 }
232
233 fn pci_address(&self) -> Option<PciAddress> {
234 self.pci_address
235 }
236
237 fn on_device_sandboxed(&mut self) {
238 if let Some(vhost_net_handle) = &self.vhost_net_handle {
242 match vhost_net_handle.set_owner() {
243 Ok(_) => {}
244 Err(e) => error!("{}: failed to set owner: {:?}", self.debug_label(), e),
245 }
246 }
247 }
248
249 fn control_notify(&self, behavior: MsixStatus) {
250 if self.worker_thread.is_none() {
251 return;
252 }
253 match behavior {
254 MsixStatus::EntryChanged(index) => {
255 if let Err(e) = self
256 .worker_client_tube
257 .send(&VhostDevRequest::MsixEntryChanged(index))
258 {
259 error!(
260 "{} failed to send VhostMsixEntryChanged request for entry {}: {:?}",
261 self.debug_label(),
262 index,
263 e
264 );
265 return;
266 }
267 if let Err(e) = self.worker_client_tube.recv::<VhostDevResponse>() {
268 error!(
269 "{} failed to receive VhostMsixEntryChanged response for entry {}: {:?}",
270 self.debug_label(),
271 index,
272 e
273 );
274 }
275 }
276 MsixStatus::Changed => {
277 if let Err(e) = self.worker_client_tube.send(&VhostDevRequest::MsixChanged) {
278 error!(
279 "{} failed to send VhostMsixChanged request: {:?}",
280 self.debug_label(),
281 e
282 );
283 return;
284 }
285 if let Err(e) = self.worker_client_tube.recv::<VhostDevResponse>() {
286 error!(
287 "{} failed to receive VhostMsixChanged response {:?}",
288 self.debug_label(),
289 e
290 );
291 }
292 }
293 _ => {}
294 }
295 }
296
297 fn reset(&mut self) -> anyhow::Result<()> {
298 if let Some(worker_thread) = self.worker_thread.take() {
299 let (worker, tap) = worker_thread.stop();
300 self.vhost_net_handle = Some(worker.vhost_handle);
301 self.tap = Some(tap);
302 self.worker_server_tube = Some(worker.server_tube);
303 }
304 Ok(())
305 }
306}
307
308#[cfg(test)]
309pub mod tests {
310 use std::net::Ipv4Addr;
311 use std::path::PathBuf;
312 use std::result;
313
314 use base::pagesize;
315 use base::Event;
316 use hypervisor::ProtectionType;
317 use net_util::sys::linux::fakes::FakeTap;
318 use net_util::TapTCommon;
319 use vhost::net::fakes::FakeNet;
320 use vm_memory::GuestAddress;
321 use vm_memory::GuestMemory;
322 use vm_memory::GuestMemoryError;
323
324 use super::*;
325 use crate::virtio::base_features;
326 use crate::virtio::QueueConfig;
327
328 fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
329 let start_addr1 = GuestAddress(0x0);
330 let start_addr2 = GuestAddress(pagesize() as u64);
331 GuestMemory::new(&[
332 (start_addr1, pagesize() as u64),
333 (start_addr2, 4 * pagesize() as u64),
334 ])
335 }
336
337 fn create_net_common() -> Net<FakeTap, FakeNet<FakeTap>> {
338 let tap = FakeTap::new(true, false).unwrap();
339 tap.set_ip_addr(Ipv4Addr::new(127, 0, 0, 1))
340 .map_err(Error::TapSetIp)
341 .unwrap();
342 tap.set_netmask(Ipv4Addr::new(255, 255, 255, 0))
343 .map_err(Error::TapSetNetmask)
344 .unwrap();
345 let mac = "de:21:e8:47:6b:6a".parse().unwrap();
346 tap.set_mac_address(mac).unwrap();
347 tap.enable().unwrap();
348
349 let features = base_features(ProtectionType::Unprotected);
350 Net::<FakeTap, FakeNet<FakeTap>>::new(
351 &PathBuf::from(""),
352 features,
353 tap,
354 Some(mac),
355 false,
356 None,
357 false,
358 )
359 .unwrap()
360 }
361
362 #[test]
363 fn create_net() {
364 create_net_common();
365 }
366
367 #[test]
368 fn keep_rds() {
369 let net = create_net_common();
370 let fds = net.keep_rds();
371 assert!(
372 !fds.is_empty(),
373 "We should have gotten at least one descriptor"
374 );
375 }
376
377 #[test]
378 fn features() {
379 let net = create_net_common();
380 const DEVICE_FEATURE_BITS: u64 = 0xffffff;
383 let expected_features = 1 << 0 | 1 << 1 | 1 << 5 | 1 << 7 | 1 << 10 | 1 << 11 | 1 << 14 | 1 << 15; assert_eq!(net.features() & DEVICE_FEATURE_BITS, expected_features);
392 }
393
394 #[test]
395 fn ack_features() {
396 let mut net = create_net_common();
397 net.ack_features(1);
399 net.ack_features(1 << 32);
400 }
401
402 #[test]
403 fn activate() {
404 let mut net = create_net_common();
405 let guest_memory = create_guest_memory().unwrap();
406 let interrupt = Interrupt::new_for_test();
407
408 let mut q0 = QueueConfig::new(1, 0);
409 q0.set_ready(true);
410 let q0 = q0
411 .activate(&guest_memory, Event::new().unwrap(), interrupt.clone())
412 .expect("QueueConfig::activate");
413
414 let mut q1 = QueueConfig::new(1, 0);
415 q1.set_ready(true);
416 let q1 = q1
417 .activate(&guest_memory, Event::new().unwrap(), interrupt.clone())
418 .expect("QueueConfig::activate");
419
420 let _ = net.activate(guest_memory, interrupt, BTreeMap::from([(0, q0), (1, q1)]));
422 }
423}