1633f51afSCathy Zhang // Copyright 2019 Intel Corporation. All Rights Reserved. 2633f51afSCathy Zhang // SPDX-License-Identifier: Apache-2.0 3633f51afSCathy Zhang 4b62a40efSSebastien Boeuf use std::sync::atomic::AtomicBool; 56bce7f79SSebastien Boeuf use std::sync::{Arc, Barrier, Mutex}; 661e57e1cSRuoqing He use std::{result, thread}; 788a9f799SRob Bradford 888a9f799SRob Bradford use net_util::{build_net_config_space, CtrlQueue, MacAddr, VirtioNetConfig}; 988a9f799SRob Bradford use seccompiler::SeccompAction; 1088a9f799SRob Bradford use serde::{Deserialize, Serialize}; 11fa8fcf5fSSebastien Boeuf use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; 124d7a4c59SBo Chen use vhost::vhost_user::{FrontendReqHandler, VhostUserFrontend, VhostUserFrontendReqHandler}; 131d55de9cSdependabot[bot] use virtio_bindings::virtio_net::{ 1492c2101fSSebastien Boeuf VIRTIO_NET_F_CSUM, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, 1592c2101fSSebastien Boeuf VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, 1692c2101fSSebastien Boeuf VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, 1776dbf85bSSebastien Boeuf VIRTIO_NET_F_MAC, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_MTU, 1892c2101fSSebastien Boeuf }; 191d55de9cSdependabot[bot] use virtio_bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; 20a423bf13SSebastien Boeuf use virtio_queue::{Queue, QueueT}; 210249e864SSebastien Boeuf use vm_memory::{ByteValued, GuestMemoryAtomic}; 2261e57e1cSRuoqing He use vm_migration::protocol::MemoryRangeTable; 2361e57e1cSRuoqing He use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable}; 24b2589d4fSRob Bradford use vmm_sys_util::eventfd::EventFd; 25633f51afSCathy Zhang 2688a9f799SRob Bradford use crate::seccomp_filters::Thread; 2788a9f799SRob Bradford use crate::thread_helper::spawn_virtio_thread; 2888a9f799SRob Bradford use crate::vhost_user::vu_common_ctrl::{VhostUserConfig, VhostUserHandle}; 2988a9f799SRob Bradford use crate::vhost_user::{Error, Result, VhostUserCommon}; 3088a9f799SRob Bradford use crate::{ 3161e57e1cSRuoqing He ActivateResult, GuestMemoryMmap, GuestRegionMmap, NetCtrlEpollHandler, VirtioCommon, 3261e57e1cSRuoqing He VirtioDevice, VirtioDeviceType, VirtioInterrupt, VIRTIO_F_IOMMU_PLATFORM, 3361e57e1cSRuoqing He VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1, 3488a9f799SRob Bradford }; 3588a9f799SRob Bradford 36652e7b9bSCathy Zhang const DEFAULT_QUEUE_NUMBER: usize = 2; 37652e7b9bSCathy Zhang 3810ab87d6SRob Bradford #[derive(Serialize, Deserialize)] 39ccafab69SSebastien Boeuf pub struct State { 40ccafab69SSebastien Boeuf pub avail_features: u64, 41ccafab69SSebastien Boeuf pub acked_features: u64, 42ccafab69SSebastien Boeuf pub config: VirtioNetConfig, 434735cb85SSebastien Boeuf pub acked_protocol_features: u64, 444735cb85SSebastien Boeuf pub vu_num_queues: usize, 45ccafab69SSebastien Boeuf } 46ccafab69SSebastien Boeuf 474d7a4c59SBo Chen struct BackendReqHandler {} 484d7a4c59SBo Chen impl VhostUserFrontendReqHandler for BackendReqHandler {} 49bc424205SSebastien Boeuf 50633f51afSCathy Zhang pub struct Net { 519d0ebf8dSRob Bradford common: VirtioCommon, 526d34ed03SSebastien Boeuf vu_common: VhostUserCommon, 53354c2a4bSSebastien Boeuf id: String, 548946a09aSSebastien Boeuf config: VirtioNetConfig, 559e53efa3SSebastien Boeuf guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>, 56e9cc23eaSSebastien Boeuf ctrl_queue_epoll_thread: Option<thread::JoinHandle<()>>, 57744e9d06SSebastien Boeuf epoll_thread: Option<thread::JoinHandle<()>>, 58e9cc23eaSSebastien Boeuf seccomp_action: SeccompAction, 59687d646cSRob Bradford exit_evt: EventFd, 603c973fa7SSebastien Boeuf iommu: bool, 61633f51afSCathy Zhang } 62633f51afSCathy Zhang 633dc7aff0SSamuel Ortiz impl Net { 64633f51afSCathy Zhang /// Create a new vhost-user-net device 653c973fa7SSebastien Boeuf #[allow(clippy::too_many_arguments)] new( id: String, mac_addr: MacAddr, mtu: Option<u16>, vu_cfg: VhostUserConfig, server: bool, seccomp_action: SeccompAction, exit_evt: EventFd, iommu: bool, state: Option<State>, offload_tso: bool, offload_ufo: bool, offload_csum: bool, ) -> Result<Net>66896b9a1dSBo Chen pub fn new( 67896b9a1dSBo Chen id: String, 68896b9a1dSBo Chen mac_addr: MacAddr, 6976dbf85bSSebastien Boeuf mtu: Option<u16>, 70896b9a1dSBo Chen vu_cfg: VhostUserConfig, 71b5c6b04bSSebastien Boeuf server: bool, 72e9cc23eaSSebastien Boeuf seccomp_action: SeccompAction, 73687d646cSRob Bradford exit_evt: EventFd, 743c973fa7SSebastien Boeuf iommu: bool, 751f0e5eb6SSebastien Boeuf state: Option<State>, 763494080eSYong He offload_tso: bool, 773494080eSYong He offload_ufo: bool, 783494080eSYong He offload_csum: bool, 79896b9a1dSBo Chen ) -> Result<Net> { 805d2df70aSSebastien Boeuf let mut num_queues = vu_cfg.num_queues; 81633f51afSCathy Zhang 821f0e5eb6SSebastien Boeuf let mut vu = 831f0e5eb6SSebastien Boeuf VhostUserHandle::connect_vhost_user(server, &vu_cfg.socket, num_queues as u64, false)?; 841f0e5eb6SSebastien Boeuf 85b62a40efSSebastien Boeuf let ( 86b62a40efSSebastien Boeuf avail_features, 87b62a40efSSebastien Boeuf acked_features, 88b62a40efSSebastien Boeuf acked_protocol_features, 89b62a40efSSebastien Boeuf vu_num_queues, 90b62a40efSSebastien Boeuf config, 91b62a40efSSebastien Boeuf paused, 92b62a40efSSebastien Boeuf ) = if let Some(state) = state { 931f0e5eb6SSebastien Boeuf info!("Restoring vhost-user-net {}", id); 941f0e5eb6SSebastien Boeuf 951f0e5eb6SSebastien Boeuf // The backend acknowledged features must not contain 961f0e5eb6SSebastien Boeuf // VIRTIO_NET_F_MAC since we don't expect the backend 971f0e5eb6SSebastien Boeuf // to handle it. 981f0e5eb6SSebastien Boeuf let backend_acked_features = state.acked_features & !(1 << VIRTIO_NET_F_MAC); 991f0e5eb6SSebastien Boeuf 1001f0e5eb6SSebastien Boeuf vu.set_protocol_features_vhost_user( 1011f0e5eb6SSebastien Boeuf backend_acked_features, 1021f0e5eb6SSebastien Boeuf state.acked_protocol_features, 1031f0e5eb6SSebastien Boeuf )?; 1041f0e5eb6SSebastien Boeuf 1051f0e5eb6SSebastien Boeuf // If the control queue feature has been negotiated, let's 1061f0e5eb6SSebastien Boeuf // increase the number of queues. 1071f0e5eb6SSebastien Boeuf if state.acked_features & (1 << VIRTIO_NET_F_CTRL_VQ) != 0 { 1081f0e5eb6SSebastien Boeuf num_queues += 1; 1094735cb85SSebastien Boeuf } 1104735cb85SSebastien Boeuf 1111f0e5eb6SSebastien Boeuf ( 1121f0e5eb6SSebastien Boeuf state.avail_features, 1131f0e5eb6SSebastien Boeuf state.acked_features, 1141f0e5eb6SSebastien Boeuf state.acked_protocol_features, 1151f0e5eb6SSebastien Boeuf state.vu_num_queues, 1161f0e5eb6SSebastien Boeuf state.config, 117b62a40efSSebastien Boeuf true, 1181f0e5eb6SSebastien Boeuf ) 1191f0e5eb6SSebastien Boeuf } else { 120633f51afSCathy Zhang // Filling device and vring features VMM supports. 121*2624f17fSRob Bradford let mut avail_features = (1 << VIRTIO_NET_F_MRG_RXBUF) 122*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_CTRL_VQ) 123*2624f17fSRob Bradford | (1 << VIRTIO_F_RING_EVENT_IDX) 124*2624f17fSRob Bradford | (1 << VIRTIO_F_VERSION_1) 125e9cc23eaSSebastien Boeuf | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(); 126633f51afSCathy Zhang 12776dbf85bSSebastien Boeuf if mtu.is_some() { 12876dbf85bSSebastien Boeuf avail_features |= 1u64 << VIRTIO_NET_F_MTU; 12976dbf85bSSebastien Boeuf } 13076dbf85bSSebastien Boeuf 1313494080eSYong He // Configure TSO/UFO features when hardware checksum offload is enabled. 1323494080eSYong He if offload_csum { 133*2624f17fSRob Bradford avail_features |= (1 << VIRTIO_NET_F_CSUM) | (1 << VIRTIO_NET_F_GUEST_CSUM); 1343494080eSYong He 1353494080eSYong He if offload_tso { 136*2624f17fSRob Bradford avail_features |= (1 << VIRTIO_NET_F_HOST_ECN) 137*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_HOST_TSO4) 138*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_HOST_TSO6) 139*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_GUEST_ECN) 140*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_GUEST_TSO4) 141*2624f17fSRob Bradford | (1 << VIRTIO_NET_F_GUEST_TSO6); 1423494080eSYong He } 1433494080eSYong He 1443494080eSYong He if offload_ufo { 145*2624f17fSRob Bradford avail_features |= (1 << VIRTIO_NET_F_HOST_UFO) | (1 << VIRTIO_NET_F_GUEST_UFO); 1463494080eSYong He } 1473494080eSYong He } 1483494080eSYong He 1495d2df70aSSebastien Boeuf let mut config = VirtioNetConfig::default(); 15076dbf85bSSebastien Boeuf build_net_config_space(&mut config, mac_addr, num_queues, mtu, &mut avail_features); 1515d2df70aSSebastien Boeuf 1525d2df70aSSebastien Boeuf let avail_protocol_features = VhostUserProtocolFeatures::MQ 1535d2df70aSSebastien Boeuf | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS 1542e3e64a4SJiachen Zhang | VhostUserProtocolFeatures::REPLY_ACK 155adae9862SSebastien Boeuf | VhostUserProtocolFeatures::INFLIGHT_SHMFD 156adae9862SSebastien Boeuf | VhostUserProtocolFeatures::LOG_SHMFD; 157e2121c5dSSebastien Boeuf 158d4b8c830SSebastien Boeuf let (mut acked_features, acked_protocol_features) = 159d4b8c830SSebastien Boeuf vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?; 160e2121c5dSSebastien Boeuf 1615d2df70aSSebastien Boeuf let backend_num_queues = 162e2121c5dSSebastien Boeuf if acked_protocol_features & VhostUserProtocolFeatures::MQ.bits() != 0 { 163d4b8c830SSebastien Boeuf vu.socket_handle() 1645d2df70aSSebastien Boeuf .get_queue_num() 165b62a40efSSebastien Boeuf .map_err(Error::VhostUserGetQueueMaxNum)? as usize 166652e7b9bSCathy Zhang } else { 1675d2df70aSSebastien Boeuf DEFAULT_QUEUE_NUMBER 168652e7b9bSCathy Zhang }; 1699e53efa3SSebastien Boeuf 1705d2df70aSSebastien Boeuf if num_queues > backend_num_queues { 1715d2df70aSSebastien Boeuf error!("vhost-user-net requested too many queues ({}) since the backend only supports {}\n", 1725d2df70aSSebastien Boeuf num_queues, backend_num_queues); 173652e7b9bSCathy Zhang return Err(Error::BadQueueNum); 174652e7b9bSCathy Zhang } 175652e7b9bSCathy Zhang 176e9cc23eaSSebastien Boeuf // If the control queue feature has been negotiated, let's increase 177e9cc23eaSSebastien Boeuf // the number of queues. 178382b37f8SSebastien Boeuf let vu_num_queues = num_queues; 179e9cc23eaSSebastien Boeuf if acked_features & (1 << VIRTIO_NET_F_CTRL_VQ) != 0 { 180e9cc23eaSSebastien Boeuf num_queues += 1; 181633f51afSCathy Zhang } 182633f51afSCathy Zhang 183e9cc23eaSSebastien Boeuf // Make sure the virtio feature to set the MAC address is exposed to 184e9cc23eaSSebastien Boeuf // the guest, even if it hasn't been negotiated with the backend. 185e9cc23eaSSebastien Boeuf acked_features |= 1 << VIRTIO_NET_F_MAC; 186e9cc23eaSSebastien Boeuf 1871f0e5eb6SSebastien Boeuf ( 1881f0e5eb6SSebastien Boeuf acked_features, 1891f0e5eb6SSebastien Boeuf // If part of the available features that have been acked, 1901f0e5eb6SSebastien Boeuf // the PROTOCOL_FEATURES bit must be already set through 1911f0e5eb6SSebastien Boeuf // the VIRTIO acked features as we know the guest would 1921f0e5eb6SSebastien Boeuf // never ack it, thus the feature would be lost. 1931f0e5eb6SSebastien Boeuf acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(), 1941f0e5eb6SSebastien Boeuf acked_protocol_features, 1951f0e5eb6SSebastien Boeuf vu_num_queues, 1961f0e5eb6SSebastien Boeuf config, 197b62a40efSSebastien Boeuf false, 1981f0e5eb6SSebastien Boeuf ) 1991f0e5eb6SSebastien Boeuf }; 2001f0e5eb6SSebastien Boeuf 201633f51afSCathy Zhang Ok(Net { 202354c2a4bSSebastien Boeuf id, 2039d0ebf8dSRob Bradford common: VirtioCommon { 204aa34d545SRob Bradford device_type: VirtioDeviceType::Net as u32, 2055d2df70aSSebastien Boeuf queue_sizes: vec![vu_cfg.queue_size; num_queues], 2061f0e5eb6SSebastien Boeuf avail_features, 2071f0e5eb6SSebastien Boeuf acked_features, 2086bce7f79SSebastien Boeuf paused_sync: Some(Arc::new(Barrier::new(2))), 2095d2df70aSSebastien Boeuf min_queues: DEFAULT_QUEUE_NUMBER as u16, 210b62a40efSSebastien Boeuf paused: Arc::new(AtomicBool::new(paused)), 211a9a13846SRob Bradford ..Default::default() 2129d0ebf8dSRob Bradford }, 2136d34ed03SSebastien Boeuf vu_common: VhostUserCommon { 214a7388086SSebastien Boeuf vu: Some(Arc::new(Mutex::new(vu))), 215e2121c5dSSebastien Boeuf acked_protocol_features, 2166bce7f79SSebastien Boeuf socket_path: vu_cfg.socket, 2176d34ed03SSebastien Boeuf vu_num_queues, 2186bce7f79SSebastien Boeuf server, 2196d34ed03SSebastien Boeuf ..Default::default() 2206d34ed03SSebastien Boeuf }, 2216d34ed03SSebastien Boeuf config, 2226d34ed03SSebastien Boeuf guest_memory: None, 223e9cc23eaSSebastien Boeuf ctrl_queue_epoll_thread: None, 224744e9d06SSebastien Boeuf epoll_thread: None, 225e9cc23eaSSebastien Boeuf seccomp_action, 226687d646cSRob Bradford exit_evt, 2273c973fa7SSebastien Boeuf iommu, 228633f51afSCathy Zhang }) 229633f51afSCathy Zhang } 230ccafab69SSebastien Boeuf state(&self) -> State231ccafab69SSebastien Boeuf fn state(&self) -> State { 232ccafab69SSebastien Boeuf State { 233ccafab69SSebastien Boeuf avail_features: self.common.avail_features, 234ccafab69SSebastien Boeuf acked_features: self.common.acked_features, 235ccafab69SSebastien Boeuf config: self.config, 2366d34ed03SSebastien Boeuf acked_protocol_features: self.vu_common.acked_protocol_features, 2376d34ed03SSebastien Boeuf vu_num_queues: self.vu_common.vu_num_queues, 238ccafab69SSebastien Boeuf } 239ccafab69SSebastien Boeuf } 240633f51afSCathy Zhang } 241633f51afSCathy Zhang 242633f51afSCathy Zhang impl Drop for Net { drop(&mut self)243633f51afSCathy Zhang fn drop(&mut self) { 24412f90569SRob Bradford if let Some(kill_evt) = self.common.kill_evt.take() { 2454b1328a2SSebastien Boeuf if let Err(e) = kill_evt.write(1) { 2464b1328a2SSebastien Boeuf error!("failed to kill vhost-user-net: {:?}", e); 2474b1328a2SSebastien Boeuf } 248633f51afSCathy Zhang } 249ad6c0ee5SPhilipp Schuster 250ad6c0ee5SPhilipp Schuster self.common.wait_for_epoll_threads(); 251ad6c0ee5SPhilipp Schuster 252ad6c0ee5SPhilipp Schuster if let Some(thread) = self.epoll_thread.take() { 253ad6c0ee5SPhilipp Schuster if let Err(e) = thread.join() { 254ad6c0ee5SPhilipp Schuster error!("Error joining thread: {:?}", e); 255ad6c0ee5SPhilipp Schuster } 256ad6c0ee5SPhilipp Schuster } 257ad6c0ee5SPhilipp Schuster if let Some(thread) = self.ctrl_queue_epoll_thread.take() { 258ad6c0ee5SPhilipp Schuster if let Err(e) = thread.join() { 259ad6c0ee5SPhilipp Schuster error!("Error joining thread: {:?}", e); 260ad6c0ee5SPhilipp Schuster } 261ad6c0ee5SPhilipp Schuster } 262633f51afSCathy Zhang } 263633f51afSCathy Zhang } 264633f51afSCathy Zhang 265633f51afSCathy Zhang impl VirtioDevice for Net { device_type(&self) -> u32266633f51afSCathy Zhang fn device_type(&self) -> u32 { 26712f90569SRob Bradford self.common.device_type 268633f51afSCathy Zhang } 269633f51afSCathy Zhang queue_max_sizes(&self) -> &[u16]270633f51afSCathy Zhang fn queue_max_sizes(&self) -> &[u16] { 27112f90569SRob Bradford &self.common.queue_sizes 272633f51afSCathy Zhang } 273633f51afSCathy Zhang features(&self) -> u6427414eddf72SCathy Zhang fn features(&self) -> u64 { 2753c973fa7SSebastien Boeuf let mut features = self.common.avail_features; 2763c973fa7SSebastien Boeuf if self.iommu { 2773c973fa7SSebastien Boeuf features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; 2783c973fa7SSebastien Boeuf } 2793c973fa7SSebastien Boeuf features 280633f51afSCathy Zhang } 281633f51afSCathy Zhang ack_features(&mut self, value: u64)28214eddf72SCathy Zhang fn ack_features(&mut self, value: u64) { 2839d0ebf8dSRob Bradford self.common.ack_features(value) 284633f51afSCathy Zhang } 285633f51afSCathy Zhang read_config(&self, offset: u64, data: &mut [u8])286751a3020SRob Bradford fn read_config(&self, offset: u64, data: &mut [u8]) { 287751a3020SRob Bradford self.read_config_from_slice(self.config.as_slice(), offset, data); 288633f51afSCathy Zhang } 289633f51afSCathy Zhang activate( &mut self, mem: GuestMemoryAtomic<GuestMemoryMmap>, interrupt_cb: Arc<dyn VirtioInterrupt>, mut queues: Vec<(usize, Queue, EventFd)>, ) -> ActivateResult290633f51afSCathy Zhang fn activate( 291633f51afSCathy Zhang &mut self, 292793d4e7bSSebastien Boeuf mem: GuestMemoryAtomic<GuestMemoryMmap>, 293c396bacaSSebastien Boeuf interrupt_cb: Arc<dyn VirtioInterrupt>, 294a423bf13SSebastien Boeuf mut queues: Vec<(usize, Queue, EventFd)>, 295633f51afSCathy Zhang ) -> ActivateResult { 2963f62a172SSebastien Boeuf self.common.activate(&queues, &interrupt_cb)?; 2979e53efa3SSebastien Boeuf self.guest_memory = Some(mem.clone()); 2989e53efa3SSebastien Boeuf 299e9cc23eaSSebastien Boeuf let num_queues = queues.len(); 300aa3ef70eSRob Bradford let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into()); 301e9cc23eaSSebastien Boeuf if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 { 302aa3ef70eSRob Bradford let ctrl_queue_index = num_queues - 1; 3033f62a172SSebastien Boeuf let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index); 304aa3ef70eSRob Bradford 305aa3ef70eSRob Bradford ctrl_queue.set_event_idx(event_idx); 306e9cc23eaSSebastien Boeuf 307280bef83SRob Bradford let (kill_evt, pause_evt) = self.common.dup_eventfds(); 308e9cc23eaSSebastien Boeuf 309e9cc23eaSSebastien Boeuf let mut ctrl_handler = NetCtrlEpollHandler { 310a423bf13SSebastien Boeuf mem: mem.clone(), 311e9cc23eaSSebastien Boeuf kill_evt, 312e9cc23eaSSebastien Boeuf pause_evt, 313e9cc23eaSSebastien Boeuf ctrl_q: CtrlQueue::new(Vec::new()), 314aa3ef70eSRob Bradford queue: ctrl_queue, 315aa3ef70eSRob Bradford queue_evt: ctrl_queue_evt, 316aa3ef70eSRob Bradford access_platform: None, 317aa3ef70eSRob Bradford interrupt_cb: interrupt_cb.clone(), 318aa3ef70eSRob Bradford queue_index: ctrl_queue_index as u16, 319e9cc23eaSSebastien Boeuf }; 320e9cc23eaSSebastien Boeuf 321e9cc23eaSSebastien Boeuf let paused = self.common.paused.clone(); 322744e9d06SSebastien Boeuf // Let's update the barrier as we need 1 for the control queue 323744e9d06SSebastien Boeuf // thread + 1 for the common vhost-user thread + 1 for the main 324744e9d06SSebastien Boeuf // thread signalling the pause. 3256bce7f79SSebastien Boeuf self.common.paused_sync = Some(Arc::new(Barrier::new(3))); 326e9cc23eaSSebastien Boeuf let paused_sync = self.common.paused_sync.clone(); 327e9cc23eaSSebastien Boeuf 32854e523c3SRob Bradford let mut epoll_threads = Vec::new(); 32954e523c3SRob Bradford spawn_virtio_thread( 33054e523c3SRob Bradford &format!("{}_ctrl", &self.id), 33154e523c3SRob Bradford &self.seccomp_action, 33254e523c3SRob Bradford Thread::VirtioVhostNetCtl, 33354e523c3SRob Bradford &mut epoll_threads, 334687d646cSRob Bradford &self.exit_evt, 335df5b803aSBo Chen move || ctrl_handler.run_ctrl(paused, paused_sync.unwrap()), 33654e523c3SRob Bradford )?; 33754e523c3SRob Bradford self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0)); 338e9cc23eaSSebastien Boeuf } 339e9cc23eaSSebastien Boeuf 3404d7a4c59SBo Chen let backend_req_handler: Option<FrontendReqHandler<BackendReqHandler>> = None; 3411a5c6631SSebastien Boeuf 3423593055eSSebastien Boeuf // The backend acknowledged features must not contain VIRTIO_NET_F_MAC 3433593055eSSebastien Boeuf // since we don't expect the backend to handle it. 3443593055eSSebastien Boeuf let backend_acked_features = self.common.acked_features & !(1 << VIRTIO_NET_F_MAC); 345e9cc23eaSSebastien Boeuf 3466bce7f79SSebastien Boeuf // Run a dedicated thread for handling potential reconnections with 3476bce7f79SSebastien Boeuf // the backend. 348280bef83SRob Bradford let (kill_evt, pause_evt) = self.common.dup_eventfds(); 3496bce7f79SSebastien Boeuf 3506d34ed03SSebastien Boeuf let mut handler = self.vu_common.activate( 3516bce7f79SSebastien Boeuf mem, 3526bce7f79SSebastien Boeuf queues, 3536d34ed03SSebastien Boeuf interrupt_cb, 3546d34ed03SSebastien Boeuf backend_acked_features, 3554d7a4c59SBo Chen backend_req_handler, 3566d34ed03SSebastien Boeuf kill_evt, 3576d34ed03SSebastien Boeuf pause_evt, 3586d34ed03SSebastien Boeuf )?; 3596bce7f79SSebastien Boeuf 3606bce7f79SSebastien Boeuf let paused = self.common.paused.clone(); 3616bce7f79SSebastien Boeuf let paused_sync = self.common.paused_sync.clone(); 3626bce7f79SSebastien Boeuf 36354e523c3SRob Bradford let mut epoll_threads = Vec::new(); 36454e523c3SRob Bradford spawn_virtio_thread( 36554e523c3SRob Bradford &self.id, 36654e523c3SRob Bradford &self.seccomp_action, 36754e523c3SRob Bradford Thread::VirtioVhostNet, 36854e523c3SRob Bradford &mut epoll_threads, 369687d646cSRob Bradford &self.exit_evt, 370df5b803aSBo Chen move || handler.run(paused, paused_sync.unwrap()), 37154e523c3SRob Bradford )?; 37254e523c3SRob Bradford self.epoll_thread = Some(epoll_threads.remove(0)); 3736bce7f79SSebastien Boeuf 374633f51afSCathy Zhang Ok(()) 375633f51afSCathy Zhang } 3764b1328a2SSebastien Boeuf reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>>37723f9ec50SRob Bradford fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 378a122da4bSSamuel Ortiz // We first must resume the virtio thread if it was paused. 37912f90569SRob Bradford if self.common.pause_evt.take().is_some() { 38012f90569SRob Bradford self.common.resume().ok()?; 381a122da4bSSamuel Ortiz } 382a122da4bSSamuel Ortiz 3836d34ed03SSebastien Boeuf if let Some(vu) = &self.vu_common.vu { 384613c60fcSSebastien Boeuf if let Err(e) = vu.lock().unwrap().reset_vhost_user() { 3854b1328a2SSebastien Boeuf error!("Failed to reset vhost-user daemon: {:?}", e); 3864b1328a2SSebastien Boeuf return None; 3874b1328a2SSebastien Boeuf } 388a7388086SSebastien Boeuf } 3894b1328a2SSebastien Boeuf 39012f90569SRob Bradford if let Some(kill_evt) = self.common.kill_evt.take() { 3914b1328a2SSebastien Boeuf // Ignore the result because there is nothing we can do about it. 3924b1328a2SSebastien Boeuf let _ = kill_evt.write(1); 3934b1328a2SSebastien Boeuf } 3944b1328a2SSebastien Boeuf 395c89095abSRob Bradford event!("virtio-device", "reset", "id", &self.id); 396c89095abSRob Bradford 39723f9ec50SRob Bradford // Return the interrupt 39823f9ec50SRob Bradford Some(self.common.interrupt_cb.take().unwrap()) 3994b1328a2SSebastien Boeuf } 40050388784SRob Bradford shutdown(&mut self)40150388784SRob Bradford fn shutdown(&mut self) { 4026d34ed03SSebastien Boeuf self.vu_common.shutdown(); 40350388784SRob Bradford } 404d75e7456SSebastien Boeuf add_memory_region( &mut self, region: &Arc<GuestRegionMmap>, ) -> std::result::Result<(), crate::Error>4059e53efa3SSebastien Boeuf fn add_memory_region( 4069e53efa3SSebastien Boeuf &mut self, 4079e53efa3SSebastien Boeuf region: &Arc<GuestRegionMmap>, 4089e53efa3SSebastien Boeuf ) -> std::result::Result<(), crate::Error> { 4096d34ed03SSebastien Boeuf self.vu_common.add_memory_region(&self.guest_memory, region) 410a7388086SSebastien Boeuf } 411633f51afSCathy Zhang } 412a122da4bSSamuel Ortiz 41312f90569SRob Bradford impl Pausable for Net { pause(&mut self) -> result::Result<(), MigratableError>41412f90569SRob Bradford fn pause(&mut self) -> result::Result<(), MigratableError> { 4156d34ed03SSebastien Boeuf self.vu_common.pause()?; 41612f90569SRob Bradford self.common.pause() 41712f90569SRob Bradford } 41812f90569SRob Bradford resume(&mut self) -> result::Result<(), MigratableError>41912f90569SRob Bradford fn resume(&mut self) -> result::Result<(), MigratableError> { 420e9cc23eaSSebastien Boeuf self.common.resume()?; 421e9cc23eaSSebastien Boeuf 422744e9d06SSebastien Boeuf if let Some(epoll_thread) = &self.epoll_thread { 423744e9d06SSebastien Boeuf epoll_thread.thread().unpark(); 4246bce7f79SSebastien Boeuf } 4256bce7f79SSebastien Boeuf 426382b37f8SSebastien Boeuf if let Some(ctrl_queue_epoll_thread) = &self.ctrl_queue_epoll_thread { 427382b37f8SSebastien Boeuf ctrl_queue_epoll_thread.thread().unpark(); 428382b37f8SSebastien Boeuf } 429382b37f8SSebastien Boeuf 4306d34ed03SSebastien Boeuf self.vu_common.resume() 43112f90569SRob Bradford } 43212f90569SRob Bradford } 43312f90569SRob Bradford 434354c2a4bSSebastien Boeuf impl Snapshottable for Net { id(&self) -> String435354c2a4bSSebastien Boeuf fn id(&self) -> String { 436354c2a4bSSebastien Boeuf self.id.clone() 437354c2a4bSSebastien Boeuf } 438ccafab69SSebastien Boeuf snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>439ccafab69SSebastien Boeuf fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 440748018acSSebastien Boeuf self.vu_common.snapshot(&self.state()) 441ccafab69SSebastien Boeuf } 442354c2a4bSSebastien Boeuf } 4431b1a2175SSamuel Ortiz impl Transportable for Net {} 4449d88e0b4SSebastien Boeuf 4459d88e0b4SSebastien Boeuf impl Migratable for Net { start_dirty_log(&mut self) -> std::result::Result<(), MigratableError>4469d88e0b4SSebastien Boeuf fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 4476d34ed03SSebastien Boeuf self.vu_common.start_dirty_log(&self.guest_memory) 4489d88e0b4SSebastien Boeuf } 4499d88e0b4SSebastien Boeuf stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError>4509d88e0b4SSebastien Boeuf fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 4516d34ed03SSebastien Boeuf self.vu_common.stop_dirty_log() 4529d88e0b4SSebastien Boeuf } 4539d88e0b4SSebastien Boeuf dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError>4549d88e0b4SSebastien Boeuf fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> { 4556d34ed03SSebastien Boeuf self.vu_common.dirty_log(&self.guest_memory) 4569d88e0b4SSebastien Boeuf } 457c85aa6dfSSebastien Boeuf start_migration(&mut self) -> std::result::Result<(), MigratableError>458a45e458cSlizhaoxin1 fn start_migration(&mut self) -> std::result::Result<(), MigratableError> { 459a45e458cSlizhaoxin1 self.vu_common.start_migration() 460a45e458cSlizhaoxin1 } 461a45e458cSlizhaoxin1 complete_migration(&mut self) -> std::result::Result<(), MigratableError>462c85aa6dfSSebastien Boeuf fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> { 4636d34ed03SSebastien Boeuf self.vu_common 4646d34ed03SSebastien Boeuf .complete_migration(self.common.kill_evt.take()) 465c85aa6dfSSebastien Boeuf } 4669d88e0b4SSebastien Boeuf } 467