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