xref: /cloud-hypervisor/virtio-devices/src/vhost_user/net.rs (revision 2624f17ffeb8f4ad4cdb6ff7460fab6e729d9a37)
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