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