xref: /cloud-hypervisor/virtio-devices/src/net.rs (revision f67b3f79ea19c9a66e04074cbbf5d292f6529e43)
1 // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 // SPDX-License-Identifier: Apache-2.0
3 //
4 // Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
5 // Use of this source code is governed by a BSD-style license that can be
6 // found in the THIRD-PARTY file.
7 
8 use super::Error as DeviceError;
9 use super::{
10     ActivateError, ActivateResult, EpollHelper, EpollHelperError, EpollHelperHandler, Queue,
11     RateLimiterConfig, VirtioCommon, VirtioDevice, VirtioDeviceType, VirtioInterruptType,
12     EPOLL_HELPER_EVENT_LAST,
13 };
14 use crate::seccomp_filters::Thread;
15 use crate::thread_helper::spawn_virtio_thread;
16 use crate::GuestMemoryMmap;
17 use crate::VirtioInterrupt;
18 use net_util::CtrlQueue;
19 use net_util::{
20     build_net_config_space, build_net_config_space_with_mq, open_tap,
21     virtio_features_to_tap_offload, MacAddr, NetCounters, NetQueuePair, OpenTapError, RxVirtio,
22     Tap, TapError, TxVirtio, VirtioNetConfig,
23 };
24 use seccompiler::SeccompAction;
25 use std::net::Ipv4Addr;
26 use std::num::Wrapping;
27 use std::os::unix::io::{AsRawFd, RawFd};
28 use std::result;
29 use std::sync::atomic::{AtomicBool, Ordering};
30 use std::sync::{Arc, Barrier};
31 use std::thread;
32 use std::vec::Vec;
33 use std::{collections::HashMap, convert::TryInto};
34 use versionize::{VersionMap, Versionize, VersionizeResult};
35 use versionize_derive::Versionize;
36 use virtio_bindings::bindings::virtio_net::*;
37 use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
38 use vm_memory::{ByteValued, GuestAddressSpace, GuestMemoryAtomic};
39 use vm_migration::VersionMapped;
40 use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
41 use vmm_sys_util::eventfd::EventFd;
42 
43 /// Control queue
44 // Event available on the control queue.
45 const CTRL_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
46 
47 pub struct NetCtrlEpollHandler {
48     pub mem: GuestMemoryAtomic<GuestMemoryMmap>,
49     pub kill_evt: EventFd,
50     pub pause_evt: EventFd,
51     pub ctrl_q: CtrlQueue,
52     pub queue_evt: EventFd,
53     pub queue: Queue,
54 }
55 
56 impl NetCtrlEpollHandler {
57     pub fn run_ctrl(
58         &mut self,
59         paused: Arc<AtomicBool>,
60         paused_sync: Arc<Barrier>,
61     ) -> std::result::Result<(), EpollHelperError> {
62         let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?;
63         helper.add_event(self.queue_evt.as_raw_fd(), CTRL_QUEUE_EVENT)?;
64         helper.run(paused, paused_sync, self)?;
65 
66         Ok(())
67     }
68 }
69 
70 impl EpollHelperHandler for NetCtrlEpollHandler {
71     fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool {
72         let ev_type = event.data as u16;
73         match ev_type {
74             CTRL_QUEUE_EVENT => {
75                 let mem = self.mem.memory();
76                 if let Err(e) = self.queue_evt.read() {
77                     error!("failed to get ctl queue event: {:?}", e);
78                     return true;
79                 }
80                 if let Err(e) = self.ctrl_q.process(&mem, &mut self.queue) {
81                     error!("failed to process ctrl queue: {:?}", e);
82                     return true;
83                 }
84             }
85             _ => {
86                 error!("Unknown event for virtio-net");
87                 return true;
88             }
89         }
90 
91         false
92     }
93 }
94 
95 /// Rx/Tx queue pair
96 // The guest has made a buffer available to receive a frame into.
97 pub const RX_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
98 // The transmit queue has a frame that is ready to send from the guest.
99 pub const TX_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
100 // A frame is available for reading from the tap device to receive in the guest.
101 pub const RX_TAP_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
102 // The TAP can be written to. Used after an EAGAIN error to retry TX.
103 pub const TX_TAP_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
104 // New 'wake up' event from the rx rate limiter
105 pub const RX_RATE_LIMITER_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 5;
106 // New 'wake up' event from the tx rate limiter
107 pub const TX_RATE_LIMITER_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 6;
108 
109 #[derive(Debug)]
110 pub enum Error {
111     /// Failed to open taps.
112     OpenTap(OpenTapError),
113 
114     // Using existing tap
115     TapError(TapError),
116 
117     // Error calling dup() on tap fd
118     DuplicateTapFd(std::io::Error),
119 }
120 
121 pub type Result<T> = result::Result<T, Error>;
122 
123 struct NetEpollHandler {
124     net: NetQueuePair,
125     interrupt_cb: Arc<dyn VirtioInterrupt>,
126     kill_evt: EventFd,
127     pause_evt: EventFd,
128     queue_pair: Vec<Queue>,
129     queue_evt_pair: Vec<EventFd>,
130     // Always generate interrupts until the driver has signalled to the device.
131     // This mitigates a problem with interrupts from tap events being "lost" upon
132     // a restore as the vCPU thread isn't ready to handle the interrupt. This causes
133     // issues when combined with VIRTIO_RING_F_EVENT_IDX interrupt suppression.
134     driver_awake: bool,
135 }
136 
137 impl NetEpollHandler {
138     fn signal_used_queue(&self, queue: &Queue) -> result::Result<(), DeviceError> {
139         self.interrupt_cb
140             .trigger(&VirtioInterruptType::Queue, Some(queue))
141             .map_err(|e| {
142                 error!("Failed to signal used queue: {:?}", e);
143                 DeviceError::FailedSignalingUsedQueue(e)
144             })
145     }
146 
147     fn handle_rx_event(&mut self) -> result::Result<(), DeviceError> {
148         let queue_evt = &self.queue_evt_pair[0];
149         if let Err(e) = queue_evt.read() {
150             error!("Failed to get rx queue event: {:?}", e);
151         }
152 
153         self.net.rx_desc_avail = true;
154 
155         let rate_limit_reached = self
156             .net
157             .rx_rate_limiter
158             .as_ref()
159             .map_or(false, |r| r.is_blocked());
160 
161         // Start to listen on RX_TAP_EVENT only when the rate limit is not reached
162         if !self.net.rx_tap_listening && !rate_limit_reached {
163             net_util::register_listener(
164                 self.net.epoll_fd.unwrap(),
165                 self.net.tap.as_raw_fd(),
166                 epoll::Events::EPOLLIN,
167                 u64::from(self.net.tap_rx_event_id),
168             )
169             .map_err(DeviceError::IoError)?;
170             self.net.rx_tap_listening = true;
171         }
172 
173         Ok(())
174     }
175 
176     fn process_tx(&mut self) -> result::Result<(), DeviceError> {
177         if self
178             .net
179             .process_tx(&mut self.queue_pair[1])
180             .map_err(DeviceError::NetQueuePair)?
181             || !self.driver_awake
182         {
183             self.signal_used_queue(&self.queue_pair[1])?;
184             debug!("Signalling TX queue");
185         } else {
186             debug!("Not signalling TX queue");
187         }
188         Ok(())
189     }
190 
191     fn handle_tx_event(&mut self) -> result::Result<(), DeviceError> {
192         let rate_limit_reached = self
193             .net
194             .tx_rate_limiter
195             .as_ref()
196             .map_or(false, |r| r.is_blocked());
197 
198         if !rate_limit_reached {
199             self.process_tx()?;
200         }
201 
202         Ok(())
203     }
204 
205     fn handle_rx_tap_event(&mut self) -> result::Result<(), DeviceError> {
206         if self
207             .net
208             .process_rx(&mut self.queue_pair[0])
209             .map_err(DeviceError::NetQueuePair)?
210             || !self.driver_awake
211         {
212             self.signal_used_queue(&self.queue_pair[0])?;
213             debug!("Signalling RX queue");
214         } else {
215             debug!("Not signalling RX queue");
216         }
217         Ok(())
218     }
219 
220     fn run(
221         &mut self,
222         paused: Arc<AtomicBool>,
223         paused_sync: Arc<Barrier>,
224     ) -> result::Result<(), EpollHelperError> {
225         let mut helper = EpollHelper::new(&self.kill_evt, &self.pause_evt)?;
226         helper.add_event(self.queue_evt_pair[0].as_raw_fd(), RX_QUEUE_EVENT)?;
227         helper.add_event(self.queue_evt_pair[1].as_raw_fd(), TX_QUEUE_EVENT)?;
228         if let Some(rate_limiter) = &self.net.rx_rate_limiter {
229             helper.add_event(rate_limiter.as_raw_fd(), RX_RATE_LIMITER_EVENT)?;
230         }
231         if let Some(rate_limiter) = &self.net.tx_rate_limiter {
232             helper.add_event(rate_limiter.as_raw_fd(), TX_RATE_LIMITER_EVENT)?;
233         }
234 
235         // If there are some already available descriptors on the RX queue,
236         // then we can start the thread while listening onto the TAP.
237         if self.queue_pair[0]
238             .available_descriptors(&self.net.mem.as_ref().unwrap().memory())
239             .unwrap()
240         {
241             helper.add_event(self.net.tap.as_raw_fd(), RX_TAP_EVENT)?;
242             self.net.rx_tap_listening = true;
243             info!("Listener registered at start");
244         }
245 
246         // The NetQueuePair needs the epoll fd.
247         self.net.epoll_fd = Some(helper.as_raw_fd());
248 
249         helper.run(paused, paused_sync, self)?;
250 
251         Ok(())
252     }
253 }
254 
255 impl EpollHelperHandler for NetEpollHandler {
256     fn handle_event(&mut self, _helper: &mut EpollHelper, event: &epoll::Event) -> bool {
257         let ev_type = event.data as u16;
258         match ev_type {
259             RX_QUEUE_EVENT => {
260                 self.driver_awake = true;
261                 if let Err(e) = self.handle_rx_event() {
262                     error!("Error processing RX queue: {:?}", e);
263                     return true;
264                 }
265             }
266             TX_QUEUE_EVENT => {
267                 let queue_evt = &self.queue_evt_pair[1];
268                 if let Err(e) = queue_evt.read() {
269                     error!("Failed to get tx queue event: {:?}", e);
270                 }
271                 self.driver_awake = true;
272                 if let Err(e) = self.handle_tx_event() {
273                     error!("Error processing TX queue: {:?}", e);
274                     return true;
275                 }
276             }
277             TX_TAP_EVENT => {
278                 if let Err(e) = self.handle_tx_event() {
279                     error!("Error processing TX queue (TAP event): {:?}", e);
280                     return true;
281                 }
282             }
283             RX_TAP_EVENT => {
284                 if let Err(e) = self.handle_rx_tap_event() {
285                     error!("Error processing tap queue: {:?}", e);
286                     return true;
287                 }
288             }
289             RX_RATE_LIMITER_EVENT => {
290                 if let Some(rate_limiter) = &mut self.net.rx_rate_limiter {
291                     // Upon rate limiter event, call the rate limiter handler and register the
292                     // TAP fd for further processing if some RX buffers are available
293                     match rate_limiter.event_handler() {
294                         Ok(_) => {
295                             if !self.net.rx_tap_listening && self.net.rx_desc_avail {
296                                 if let Err(e) = net_util::register_listener(
297                                     self.net.epoll_fd.unwrap(),
298                                     self.net.tap.as_raw_fd(),
299                                     epoll::Events::EPOLLIN,
300                                     u64::from(self.net.tap_rx_event_id),
301                                 ) {
302                                     error!("Error register_listener with `RX_RATE_LIMITER_EVENT`: {:?}", e);
303                                     return true;
304                                 }
305                                 self.net.rx_tap_listening = true;
306                             }
307                         }
308                         Err(e) => {
309                             error!("Error from 'rate_limiter.event_handler()': {:?}", e);
310                             return true;
311                         }
312                     }
313                 } else {
314                     error!("Unexpected RX_RATE_LIMITER_EVENT");
315                     return true;
316                 }
317             }
318             TX_RATE_LIMITER_EVENT => {
319                 if let Some(rate_limiter) = &mut self.net.tx_rate_limiter {
320                     // Upon rate limiter event, call the rate limiter handler
321                     // and restart processing the queue.
322                     match rate_limiter.event_handler() {
323                         Ok(_) => {
324                             self.driver_awake = true;
325                             if let Err(e) = self.process_tx() {
326                                 error!("Error processing TX queue: {:?}", e);
327                                 return true;
328                             }
329                         }
330                         Err(e) => {
331                             error!("Error from 'rate_limiter.event_handler()': {:?}", e);
332                             return true;
333                         }
334                     }
335                 } else {
336                     error!("Unexpected TX_RATE_LIMITER_EVENT");
337                     return true;
338                 }
339             }
340             _ => {
341                 error!("Unknown event: {}", ev_type);
342                 return true;
343             }
344         }
345         false
346     }
347 }
348 
349 pub struct Net {
350     common: VirtioCommon,
351     id: String,
352     taps: Vec<Tap>,
353     config: VirtioNetConfig,
354     ctrl_queue_epoll_thread: Option<thread::JoinHandle<()>>,
355     counters: NetCounters,
356     seccomp_action: SeccompAction,
357     rate_limiter_config: Option<RateLimiterConfig>,
358     exit_evt: EventFd,
359 }
360 
361 #[derive(Versionize)]
362 pub struct NetState {
363     pub avail_features: u64,
364     pub acked_features: u64,
365     pub config: VirtioNetConfig,
366     pub queue_size: Vec<u16>,
367 }
368 
369 impl VersionMapped for NetState {}
370 
371 impl Net {
372     /// Create a new virtio network device with the given TAP interface.
373     #[allow(clippy::too_many_arguments)]
374     pub fn new_with_tap(
375         id: String,
376         taps: Vec<Tap>,
377         guest_mac: Option<MacAddr>,
378         iommu: bool,
379         num_queues: usize,
380         queue_size: u16,
381         seccomp_action: SeccompAction,
382         rate_limiter_config: Option<RateLimiterConfig>,
383         exit_evt: EventFd,
384     ) -> Result<Self> {
385         let mut avail_features = 1 << VIRTIO_NET_F_CSUM
386             | 1 << VIRTIO_NET_F_CTRL_GUEST_OFFLOADS
387             | 1 << VIRTIO_NET_F_GUEST_CSUM
388             | 1 << VIRTIO_NET_F_GUEST_ECN
389             | 1 << VIRTIO_NET_F_GUEST_TSO4
390             | 1 << VIRTIO_NET_F_GUEST_TSO6
391             | 1 << VIRTIO_NET_F_GUEST_UFO
392             | 1 << VIRTIO_NET_F_HOST_ECN
393             | 1 << VIRTIO_NET_F_HOST_TSO4
394             | 1 << VIRTIO_NET_F_HOST_TSO6
395             | 1 << VIRTIO_NET_F_HOST_UFO
396             | 1 << VIRTIO_RING_F_EVENT_IDX
397             | 1 << VIRTIO_F_VERSION_1;
398 
399         if iommu {
400             avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
401         }
402 
403         avail_features |= 1 << VIRTIO_NET_F_CTRL_VQ;
404         let queue_num = num_queues + 1;
405 
406         let mut config = VirtioNetConfig::default();
407         if let Some(mac) = guest_mac {
408             build_net_config_space(&mut config, mac, num_queues, &mut avail_features);
409         } else {
410             build_net_config_space_with_mq(&mut config, num_queues, &mut avail_features);
411         }
412 
413         Ok(Net {
414             common: VirtioCommon {
415                 device_type: VirtioDeviceType::Net as u32,
416                 avail_features,
417                 queue_sizes: vec![queue_size; queue_num],
418                 paused_sync: Some(Arc::new(Barrier::new((num_queues / 2) + 1))),
419                 min_queues: 2,
420                 ..Default::default()
421             },
422             id,
423             taps,
424             config,
425             ctrl_queue_epoll_thread: None,
426             counters: NetCounters::default(),
427             seccomp_action,
428             rate_limiter_config,
429             exit_evt,
430         })
431     }
432 
433     /// Create a new virtio network device with the given IP address and
434     /// netmask.
435     #[allow(clippy::too_many_arguments)]
436     pub fn new(
437         id: String,
438         if_name: Option<&str>,
439         ip_addr: Option<Ipv4Addr>,
440         netmask: Option<Ipv4Addr>,
441         guest_mac: Option<MacAddr>,
442         host_mac: &mut Option<MacAddr>,
443         iommu: bool,
444         num_queues: usize,
445         queue_size: u16,
446         seccomp_action: SeccompAction,
447         rate_limiter_config: Option<RateLimiterConfig>,
448         exit_evt: EventFd,
449     ) -> Result<Self> {
450         let taps = open_tap(if_name, ip_addr, netmask, host_mac, num_queues / 2, None)
451             .map_err(Error::OpenTap)?;
452 
453         Self::new_with_tap(
454             id,
455             taps,
456             guest_mac,
457             iommu,
458             num_queues,
459             queue_size,
460             seccomp_action,
461             rate_limiter_config,
462             exit_evt,
463         )
464     }
465 
466     #[allow(clippy::too_many_arguments)]
467     pub fn from_tap_fds(
468         id: String,
469         fds: &[RawFd],
470         guest_mac: Option<MacAddr>,
471         iommu: bool,
472         queue_size: u16,
473         seccomp_action: SeccompAction,
474         rate_limiter_config: Option<RateLimiterConfig>,
475         exit_evt: EventFd,
476     ) -> Result<Self> {
477         let mut taps: Vec<Tap> = Vec::new();
478         let num_queue_pairs = fds.len();
479 
480         for fd in fds.iter() {
481             // Duplicate so that it can survive reboots
482             let fd = unsafe { libc::dup(*fd) };
483             if fd < 0 {
484                 return Err(Error::DuplicateTapFd(std::io::Error::last_os_error()));
485             }
486             let tap = Tap::from_tap_fd(fd, num_queue_pairs).map_err(Error::TapError)?;
487             taps.push(tap);
488         }
489 
490         Self::new_with_tap(
491             id,
492             taps,
493             guest_mac,
494             iommu,
495             num_queue_pairs * 2,
496             queue_size,
497             seccomp_action,
498             rate_limiter_config,
499             exit_evt,
500         )
501     }
502 
503     fn state(&self) -> NetState {
504         NetState {
505             avail_features: self.common.avail_features,
506             acked_features: self.common.acked_features,
507             config: self.config,
508             queue_size: self.common.queue_sizes.clone(),
509         }
510     }
511 
512     fn set_state(&mut self, state: &NetState) {
513         self.common.avail_features = state.avail_features;
514         self.common.acked_features = state.acked_features;
515         self.config = state.config;
516         self.common.queue_sizes = state.queue_size.clone();
517     }
518 }
519 
520 impl Drop for Net {
521     fn drop(&mut self) {
522         if let Some(kill_evt) = self.common.kill_evt.take() {
523             // Ignore the result because there is nothing we can do about it.
524             let _ = kill_evt.write(1);
525         }
526     }
527 }
528 
529 impl VirtioDevice for Net {
530     fn device_type(&self) -> u32 {
531         self.common.device_type
532     }
533 
534     fn queue_max_sizes(&self) -> &[u16] {
535         &self.common.queue_sizes
536     }
537 
538     fn features(&self) -> u64 {
539         self.common.avail_features
540     }
541 
542     fn ack_features(&mut self, value: u64) {
543         self.common.ack_features(value)
544     }
545 
546     fn read_config(&self, offset: u64, data: &mut [u8]) {
547         self.read_config_from_slice(self.config.as_slice(), offset, data);
548     }
549 
550     fn activate(
551         &mut self,
552         mem: GuestMemoryAtomic<GuestMemoryMmap>,
553         interrupt_cb: Arc<dyn VirtioInterrupt>,
554         mut queues: Vec<Queue>,
555         mut queue_evts: Vec<EventFd>,
556     ) -> ActivateResult {
557         self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
558 
559         let queue_num = queues.len();
560         if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && queue_num % 2 != 0 {
561             let cvq_queue = queues.remove(queue_num - 1);
562             let cvq_queue_evt = queue_evts.remove(queue_num - 1);
563 
564             let (kill_evt, pause_evt) = self.common.dup_eventfds();
565             let mut ctrl_handler = NetCtrlEpollHandler {
566                 mem: mem.clone(),
567                 kill_evt,
568                 pause_evt,
569                 ctrl_q: CtrlQueue::new(self.taps.clone()),
570                 queue: cvq_queue,
571                 queue_evt: cvq_queue_evt,
572             };
573 
574             let paused = self.common.paused.clone();
575             // Let's update the barrier as we need 1 for each RX/TX pair +
576             // 1 for the control queue + 1 for the main thread signalling
577             // the pause.
578             self.common.paused_sync = Some(Arc::new(Barrier::new(self.taps.len() + 2)));
579             let paused_sync = self.common.paused_sync.clone();
580 
581             let mut epoll_threads = Vec::new();
582             spawn_virtio_thread(
583                 &format!("{}_ctrl", &self.id),
584                 &self.seccomp_action,
585                 Thread::VirtioNetCtl,
586                 &mut epoll_threads,
587                 &self.exit_evt,
588                 move || {
589                     if let Err(e) = ctrl_handler.run_ctrl(paused, paused_sync.unwrap()) {
590                         error!("Error running worker: {:?}", e);
591                     }
592                 },
593             )?;
594             self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0));
595         }
596 
597         let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into());
598 
599         let mut epoll_threads = Vec::new();
600         let mut taps = self.taps.clone();
601         for i in 0..queues.len() / 2 {
602             let rx = RxVirtio::new();
603             let tx = TxVirtio::new();
604             let rx_tap_listening = false;
605 
606             let mut queue_pair = vec![queues.remove(0), queues.remove(0)];
607             queue_pair[0].set_event_idx(event_idx);
608             queue_pair[1].set_event_idx(event_idx);
609 
610             let queue_evt_pair = vec![queue_evts.remove(0), queue_evts.remove(0)];
611 
612             let (kill_evt, pause_evt) = self.common.dup_eventfds();
613 
614             let rx_rate_limiter: Option<rate_limiter::RateLimiter> = self
615                 .rate_limiter_config
616                 .map(RateLimiterConfig::try_into)
617                 .transpose()
618                 .map_err(ActivateError::CreateRateLimiter)?;
619 
620             let tx_rate_limiter: Option<rate_limiter::RateLimiter> = self
621                 .rate_limiter_config
622                 .map(RateLimiterConfig::try_into)
623                 .transpose()
624                 .map_err(ActivateError::CreateRateLimiter)?;
625 
626             let tap = taps.remove(0);
627             tap.set_offload(virtio_features_to_tap_offload(self.common.acked_features))
628                 .map_err(|e| {
629                     error!("Error programming tap offload: {:?}", e);
630                     ActivateError::BadActivate
631                 })?;
632 
633             let mut handler = NetEpollHandler {
634                 net: NetQueuePair {
635                     mem: Some(mem.clone()),
636                     tap_for_write_epoll: tap.clone(),
637                     tap,
638                     rx,
639                     tx,
640                     epoll_fd: None,
641                     rx_tap_listening,
642                     tx_tap_listening: false,
643                     counters: self.counters.clone(),
644                     tap_rx_event_id: RX_TAP_EVENT,
645                     tap_tx_event_id: TX_TAP_EVENT,
646                     rx_desc_avail: false,
647                     rx_rate_limiter,
648                     tx_rate_limiter,
649                 },
650                 queue_pair,
651                 queue_evt_pair,
652                 interrupt_cb: interrupt_cb.clone(),
653                 kill_evt,
654                 pause_evt,
655                 driver_awake: false,
656             };
657 
658             let paused = self.common.paused.clone();
659             let paused_sync = self.common.paused_sync.clone();
660 
661             spawn_virtio_thread(
662                 &format!("{}_qp{}", self.id.clone(), i),
663                 &self.seccomp_action,
664                 Thread::VirtioNet,
665                 &mut epoll_threads,
666                 &self.exit_evt,
667                 move || {
668                     if let Err(e) = handler.run(paused, paused_sync.unwrap()) {
669                         error!("Error running worker: {:?}", e);
670                     }
671                 },
672             )?;
673         }
674 
675         self.common.epoll_threads = Some(epoll_threads);
676 
677         event!("virtio-device", "activated", "id", &self.id);
678         Ok(())
679     }
680 
681     fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
682         let result = self.common.reset();
683         event!("virtio-device", "reset", "id", &self.id);
684         result
685     }
686 
687     fn counters(&self) -> Option<HashMap<&'static str, Wrapping<u64>>> {
688         let mut counters = HashMap::new();
689 
690         counters.insert(
691             "rx_bytes",
692             Wrapping(self.counters.rx_bytes.load(Ordering::Acquire)),
693         );
694         counters.insert(
695             "rx_frames",
696             Wrapping(self.counters.rx_frames.load(Ordering::Acquire)),
697         );
698         counters.insert(
699             "tx_bytes",
700             Wrapping(self.counters.tx_bytes.load(Ordering::Acquire)),
701         );
702         counters.insert(
703             "tx_frames",
704             Wrapping(self.counters.tx_frames.load(Ordering::Acquire)),
705         );
706 
707         Some(counters)
708     }
709 }
710 
711 impl Pausable for Net {
712     fn pause(&mut self) -> result::Result<(), MigratableError> {
713         self.common.pause()
714     }
715 
716     fn resume(&mut self) -> result::Result<(), MigratableError> {
717         self.common.resume()?;
718 
719         if let Some(ctrl_queue_epoll_thread) = &self.ctrl_queue_epoll_thread {
720             ctrl_queue_epoll_thread.thread().unpark();
721         }
722         Ok(())
723     }
724 }
725 
726 impl Snapshottable for Net {
727     fn id(&self) -> String {
728         self.id.clone()
729     }
730 
731     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
732         Snapshot::new_from_versioned_state(&self.id, &self.state())
733     }
734 
735     fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
736         self.set_state(&snapshot.to_versioned_state(&self.id)?);
737         Ok(())
738     }
739 }
740 impl Transportable for Net {}
741 impl Migratable for Net {}
742