• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::mem;
6 use std::net::Ipv4Addr;
7 use std::path::Path;
8 use std::thread;
9 
10 use net_util::{MacAddress, TapT};
11 
12 use base::{error, warn, AsRawDescriptor, Event, RawDescriptor, Tube};
13 use vhost::NetT as VhostNetT;
14 use virtio_sys::virtio_net;
15 use vm_memory::GuestMemory;
16 
17 use super::control_socket::*;
18 use super::worker::Worker;
19 use super::{Error, Result};
20 use crate::pci::MsixStatus;
21 use crate::virtio::{Interrupt, Queue, VirtioDevice, TYPE_NET};
22 
23 const QUEUE_SIZE: u16 = 256;
24 const NUM_QUEUES: usize = 2;
25 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
26 
27 pub struct Net<T: TapT, U: VhostNetT<T>> {
28     workers_kill_evt: Option<Event>,
29     kill_evt: Event,
30     worker_thread: Option<thread::JoinHandle<(Worker<U>, T)>>,
31     tap: Option<T>,
32     vhost_net_handle: Option<U>,
33     vhost_interrupt: Option<Vec<Event>>,
34     avail_features: u64,
35     acked_features: u64,
36     request_tube: Tube,
37     response_tube: Option<Tube>,
38 }
39 
40 impl<T, U> Net<T, U>
41 where
42     T: TapT,
43     U: VhostNetT<T>,
44 {
45     /// Create a new virtio network device with the given IP address and
46     /// netmask.
new( vhost_net_device_path: &Path, base_features: u64, ip_addr: Ipv4Addr, netmask: Ipv4Addr, mac_addr: MacAddress, ) -> Result<Net<T, U>>47     pub fn new(
48         vhost_net_device_path: &Path,
49         base_features: u64,
50         ip_addr: Ipv4Addr,
51         netmask: Ipv4Addr,
52         mac_addr: MacAddress,
53     ) -> Result<Net<T, U>> {
54         let kill_evt = Event::new().map_err(Error::CreateKillEvent)?;
55 
56         let tap: T = T::new(true, false).map_err(Error::TapOpen)?;
57         tap.set_ip_addr(ip_addr).map_err(Error::TapSetIp)?;
58         tap.set_netmask(netmask).map_err(Error::TapSetNetmask)?;
59         tap.set_mac_address(mac_addr)
60             .map_err(Error::TapSetMacAddress)?;
61 
62         // Set offload flags to match the virtio features below.
63         tap.set_offload(
64             net_sys::TUN_F_CSUM | net_sys::TUN_F_UFO | net_sys::TUN_F_TSO4 | net_sys::TUN_F_TSO6,
65         )
66         .map_err(Error::TapSetOffload)?;
67 
68         // We declare VIRTIO_NET_F_MRG_RXBUF, so set the vnet hdr size to match.
69         let vnet_hdr_size = mem::size_of::<virtio_net::virtio_net_hdr_mrg_rxbuf>() as i32;
70         tap.set_vnet_hdr_size(vnet_hdr_size)
71             .map_err(Error::TapSetVnetHdrSize)?;
72 
73         tap.enable().map_err(Error::TapEnable)?;
74         let vhost_net_handle = U::new(vhost_net_device_path).map_err(Error::VhostOpen)?;
75 
76         let avail_features = base_features
77             | 1 << virtio_net::VIRTIO_NET_F_GUEST_CSUM
78             | 1 << virtio_net::VIRTIO_NET_F_CSUM
79             | 1 << virtio_net::VIRTIO_NET_F_GUEST_TSO4
80             | 1 << virtio_net::VIRTIO_NET_F_GUEST_UFO
81             | 1 << virtio_net::VIRTIO_NET_F_HOST_TSO4
82             | 1 << virtio_net::VIRTIO_NET_F_HOST_UFO
83             | 1 << virtio_net::VIRTIO_NET_F_MRG_RXBUF
84             | 1 << virtio_sys::vhost::VIRTIO_RING_F_INDIRECT_DESC
85             | 1 << virtio_sys::vhost::VIRTIO_RING_F_EVENT_IDX
86             | 1 << virtio_sys::vhost::VIRTIO_F_NOTIFY_ON_EMPTY;
87 
88         let mut vhost_interrupt = Vec::new();
89         for _ in 0..NUM_QUEUES {
90             vhost_interrupt.push(Event::new().map_err(Error::VhostIrqCreate)?);
91         }
92 
93         let (request_tube, response_tube) = Tube::pair().map_err(Error::CreateTube)?;
94 
95         Ok(Net {
96             workers_kill_evt: Some(kill_evt.try_clone().map_err(Error::CloneKillEvent)?),
97             kill_evt,
98             worker_thread: None,
99             tap: Some(tap),
100             vhost_net_handle: Some(vhost_net_handle),
101             vhost_interrupt: Some(vhost_interrupt),
102             avail_features,
103             acked_features: 0u64,
104             request_tube,
105             response_tube: Some(response_tube),
106         })
107     }
108 }
109 
110 impl<T, U> Drop for Net<T, U>
111 where
112     T: TapT,
113     U: VhostNetT<T>,
114 {
drop(&mut self)115     fn drop(&mut self) {
116         // Only kill the child if it claimed its event.
117         if self.workers_kill_evt.is_none() {
118             // Ignore the result because there is nothing we can do about it.
119             let _ = self.kill_evt.write(1);
120         }
121 
122         if let Some(worker_thread) = self.worker_thread.take() {
123             let _ = worker_thread.join();
124         }
125     }
126 }
127 
128 impl<T, U> VirtioDevice for Net<T, U>
129 where
130     T: TapT + 'static,
131     U: VhostNetT<T> + 'static,
132 {
keep_rds(&self) -> Vec<RawDescriptor>133     fn keep_rds(&self) -> Vec<RawDescriptor> {
134         let mut keep_rds = Vec::new();
135 
136         if let Some(tap) = &self.tap {
137             keep_rds.push(tap.as_raw_descriptor());
138         }
139 
140         if let Some(vhost_net_handle) = &self.vhost_net_handle {
141             keep_rds.push(vhost_net_handle.as_raw_descriptor());
142         }
143 
144         if let Some(vhost_interrupt) = &self.vhost_interrupt {
145             for vhost_int in vhost_interrupt.iter() {
146                 keep_rds.push(vhost_int.as_raw_descriptor());
147             }
148         }
149 
150         if let Some(workers_kill_evt) = &self.workers_kill_evt {
151             keep_rds.push(workers_kill_evt.as_raw_descriptor());
152         }
153         keep_rds.push(self.kill_evt.as_raw_descriptor());
154 
155         keep_rds.push(self.request_tube.as_raw_descriptor());
156 
157         if let Some(response_tube) = &self.response_tube {
158             keep_rds.push(response_tube.as_raw_descriptor());
159         }
160 
161         keep_rds
162     }
163 
device_type(&self) -> u32164     fn device_type(&self) -> u32 {
165         TYPE_NET
166     }
167 
queue_max_sizes(&self) -> &[u16]168     fn queue_max_sizes(&self) -> &[u16] {
169         QUEUE_SIZES
170     }
171 
features(&self) -> u64172     fn features(&self) -> u64 {
173         self.avail_features
174     }
175 
ack_features(&mut self, value: u64)176     fn ack_features(&mut self, value: u64) {
177         let mut v = value;
178 
179         // Check if the guest is ACK'ing a feature that we didn't claim to have.
180         let unrequested_features = v & !self.avail_features;
181         if unrequested_features != 0 {
182             warn!("net: virtio net got unknown feature ack: {:x}", v);
183 
184             // Don't count these features as acked.
185             v &= !unrequested_features;
186         }
187         self.acked_features |= v;
188     }
189 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: Vec<Queue>, queue_evts: Vec<Event>, )190     fn activate(
191         &mut self,
192         mem: GuestMemory,
193         interrupt: Interrupt,
194         queues: Vec<Queue>,
195         queue_evts: Vec<Event>,
196     ) {
197         if queues.len() != NUM_QUEUES || queue_evts.len() != NUM_QUEUES {
198             error!("net: expected {} queues, got {}", NUM_QUEUES, queues.len());
199             return;
200         }
201 
202         if let Some(vhost_net_handle) = self.vhost_net_handle.take() {
203             if let Some(tap) = self.tap.take() {
204                 if let Some(vhost_interrupt) = self.vhost_interrupt.take() {
205                     if let Some(kill_evt) = self.workers_kill_evt.take() {
206                         let acked_features = self.acked_features;
207                         let socket = if self.response_tube.is_some() {
208                             self.response_tube.take()
209                         } else {
210                             None
211                         };
212                         let mut worker = Worker::new(
213                             queues,
214                             vhost_net_handle,
215                             vhost_interrupt,
216                             interrupt,
217                             acked_features,
218                             kill_evt,
219                             socket,
220                         );
221                         let activate_vqs = |handle: &U| -> Result<()> {
222                             for idx in 0..NUM_QUEUES {
223                                 handle
224                                     .set_backend(idx, Some(&tap))
225                                     .map_err(Error::VhostNetSetBackend)?;
226                             }
227                             Ok(())
228                         };
229                         let result = worker.init(mem, queue_evts, QUEUE_SIZES, activate_vqs);
230                         if let Err(e) = result {
231                             error!("net worker thread exited with error: {}", e);
232                         }
233                         let worker_result = thread::Builder::new()
234                             .name("vhost_net".to_string())
235                             .spawn(move || {
236                                 let cleanup_vqs = |handle: &U| -> Result<()> {
237                                     for idx in 0..NUM_QUEUES {
238                                         handle
239                                             .set_backend(idx, None)
240                                             .map_err(Error::VhostNetSetBackend)?;
241                                     }
242                                     Ok(())
243                                 };
244                                 let result = worker.run(cleanup_vqs);
245                                 if let Err(e) = result {
246                                     error!("net worker thread exited with error: {}", e);
247                                 }
248                                 (worker, tap)
249                             });
250 
251                         match worker_result {
252                             Err(e) => {
253                                 error!("failed to spawn vhost_net worker: {}", e);
254                                 return;
255                             }
256                             Ok(join_handle) => {
257                                 self.worker_thread = Some(join_handle);
258                             }
259                         }
260                     }
261                 }
262             }
263         }
264     }
265 
on_device_sandboxed(&mut self)266     fn on_device_sandboxed(&mut self) {
267         // ignore the error but to log the error. We don't need to do
268         // anything here because when activate, the other vhost set up
269         // will be failed to stop the activate thread.
270         if let Some(vhost_net_handle) = &self.vhost_net_handle {
271             match vhost_net_handle.set_owner() {
272                 Ok(_) => {}
273                 Err(e) => error!("{}: failed to set owner: {:?}", self.debug_label(), e),
274             }
275         }
276     }
277 
control_notify(&self, behavior: MsixStatus)278     fn control_notify(&self, behavior: MsixStatus) {
279         if self.worker_thread.is_none() {
280             return;
281         }
282         match behavior {
283             MsixStatus::EntryChanged(index) => {
284                 if let Err(e) = self
285                     .request_tube
286                     .send(&VhostDevRequest::MsixEntryChanged(index))
287                 {
288                     error!(
289                         "{} failed to send VhostMsixEntryChanged request for entry {}: {:?}",
290                         self.debug_label(),
291                         index,
292                         e
293                     );
294                     return;
295                 }
296                 if let Err(e) = self.request_tube.recv::<VhostDevResponse>() {
297                     error!(
298                         "{} failed to receive VhostMsixEntryChanged response for entry {}: {:?}",
299                         self.debug_label(),
300                         index,
301                         e
302                     );
303                 }
304             }
305             MsixStatus::Changed => {
306                 if let Err(e) = self.request_tube.send(&VhostDevRequest::MsixChanged) {
307                     error!(
308                         "{} failed to send VhostMsixChanged request: {:?}",
309                         self.debug_label(),
310                         e
311                     );
312                     return;
313                 }
314                 if let Err(e) = self.request_tube.recv::<VhostDevResponse>() {
315                     error!(
316                         "{} failed to receive VhostMsixChanged response {:?}",
317                         self.debug_label(),
318                         e
319                     );
320                 }
321             }
322             _ => {}
323         }
324     }
325 
reset(&mut self) -> bool326     fn reset(&mut self) -> bool {
327         // Only kill the child if it claimed its event.
328         if self.workers_kill_evt.is_none() && self.kill_evt.write(1).is_err() {
329             error!("{}: failed to notify the kill event", self.debug_label());
330             return false;
331         }
332 
333         if let Some(worker_thread) = self.worker_thread.take() {
334             match worker_thread.join() {
335                 Err(_) => {
336                     error!("{}: failed to get back resources", self.debug_label());
337                     return false;
338                 }
339                 Ok((worker, tap)) => {
340                     self.vhost_net_handle = Some(worker.vhost_handle);
341                     self.tap = Some(tap);
342                     self.vhost_interrupt = Some(worker.vhost_interrupt);
343                     self.workers_kill_evt = Some(worker.kill_evt);
344                     self.response_tube = worker.response_tube;
345                     return true;
346                 }
347             }
348         }
349         false
350     }
351 }
352 
353 #[cfg(test)]
354 pub mod tests {
355     use super::*;
356     use crate::virtio::base_features;
357     use crate::virtio::VIRTIO_MSI_NO_VECTOR;
358     use crate::IrqLevelEvent;
359     use hypervisor::ProtectionType;
360     use net_util::fakes::FakeTap;
361     use std::path::PathBuf;
362     use std::result;
363     use std::sync::atomic::AtomicUsize;
364     use std::sync::Arc;
365     use vhost::net::fakes::FakeNet;
366     use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
367 
create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError>368     fn create_guest_memory() -> result::Result<GuestMemory, GuestMemoryError> {
369         let start_addr1 = GuestAddress(0x0);
370         let start_addr2 = GuestAddress(0x1000);
371         GuestMemory::new(&[(start_addr1, 0x1000), (start_addr2, 0x4000)])
372     }
373 
create_net_common() -> Net<FakeTap, FakeNet<FakeTap>>374     fn create_net_common() -> Net<FakeTap, FakeNet<FakeTap>> {
375         let features = base_features(ProtectionType::Unprotected);
376         Net::<FakeTap, FakeNet<FakeTap>>::new(
377             &PathBuf::from(""),
378             features,
379             Ipv4Addr::new(127, 0, 0, 1),
380             Ipv4Addr::new(255, 255, 255, 0),
381             "de:21:e8:47:6b:6a".parse().unwrap(),
382         )
383         .unwrap()
384     }
385 
386     #[test]
create_net()387     fn create_net() {
388         create_net_common();
389     }
390 
391     #[test]
keep_rds()392     fn keep_rds() {
393         let net = create_net_common();
394         let fds = net.keep_rds();
395         assert!(!fds.is_empty(), "We should have gotten at least one fd");
396     }
397 
398     #[test]
features()399     fn features() {
400         let net = create_net_common();
401         assert_eq!(net.features(), 5117103235);
402     }
403 
404     #[test]
ack_features()405     fn ack_features() {
406         let mut net = create_net_common();
407         // Just testing that we don't panic, for now
408         net.ack_features(1);
409         net.ack_features(1 << 32);
410     }
411 
412     #[test]
activate()413     fn activate() {
414         let mut net = create_net_common();
415         let guest_memory = create_guest_memory().unwrap();
416         // Just testing that we don't panic, for now
417         net.activate(
418             guest_memory,
419             Interrupt::new(
420                 Arc::new(AtomicUsize::new(0)),
421                 IrqLevelEvent::new().unwrap(),
422                 None,
423                 VIRTIO_MSI_NO_VECTOR,
424             ),
425             vec![Queue::new(1)],
426             vec![Event::new().unwrap()],
427         );
428     }
429 }
430