1 // Copyright 2019 Intel Corporation. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 use crate::seccomp_filters::Thread; 5 use crate::thread_helper::spawn_virtio_thread; 6 use crate::vhost_user::vu_common_ctrl::{VhostUserConfig, VhostUserHandle}; 7 use crate::vhost_user::{Error, Result, VhostUserCommon}; 8 use crate::{ 9 ActivateResult, NetCtrlEpollHandler, VirtioCommon, VirtioDevice, VirtioDeviceType, 10 VirtioInterrupt, VIRTIO_F_IOMMU_PLATFORM, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_VERSION_1, 11 }; 12 use crate::{GuestMemoryMmap, GuestRegionMmap}; 13 use net_util::{build_net_config_space, CtrlQueue, MacAddr, VirtioNetConfig}; 14 use seccompiler::SeccompAction; 15 use std::result; 16 use std::sync::{Arc, Barrier, Mutex}; 17 use std::thread; 18 use std::vec::Vec; 19 use versionize::{VersionMap, Versionize, VersionizeResult}; 20 use versionize_derive::Versionize; 21 use vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures}; 22 use vhost::vhost_user::{MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler}; 23 use virtio_bindings::bindings::virtio_net::{ 24 VIRTIO_NET_F_CSUM, VIRTIO_NET_F_CTRL_VQ, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_GUEST_ECN, 25 VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_UFO, 26 VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, 27 VIRTIO_NET_F_MAC, VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_MTU, 28 }; 29 use virtio_bindings::bindings::virtio_ring::VIRTIO_RING_F_EVENT_IDX; 30 use virtio_queue::{Queue, QueueT}; 31 use vm_memory::{ByteValued, GuestMemoryAtomic}; 32 use vm_migration::{ 33 protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot, Snapshottable, 34 Transportable, VersionMapped, 35 }; 36 use vmm_sys_util::eventfd::EventFd; 37 38 const DEFAULT_QUEUE_NUMBER: usize = 2; 39 40 #[derive(Versionize)] 41 pub struct State { 42 pub avail_features: u64, 43 pub acked_features: u64, 44 pub config: VirtioNetConfig, 45 pub acked_protocol_features: u64, 46 pub vu_num_queues: usize, 47 } 48 49 impl VersionMapped for State {} 50 51 struct SlaveReqHandler {} 52 impl VhostUserMasterReqHandler for SlaveReqHandler {} 53 54 pub struct Net { 55 common: VirtioCommon, 56 vu_common: VhostUserCommon, 57 id: String, 58 config: VirtioNetConfig, 59 guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>, 60 ctrl_queue_epoll_thread: Option<thread::JoinHandle<()>>, 61 epoll_thread: Option<thread::JoinHandle<()>>, 62 seccomp_action: SeccompAction, 63 exit_evt: EventFd, 64 iommu: bool, 65 } 66 67 impl Net { 68 /// Create a new vhost-user-net device 69 #[allow(clippy::too_many_arguments)] 70 pub fn new( 71 id: String, 72 mac_addr: MacAddr, 73 mtu: Option<u16>, 74 vu_cfg: VhostUserConfig, 75 server: bool, 76 seccomp_action: SeccompAction, 77 exit_evt: EventFd, 78 iommu: bool, 79 state: Option<State>, 80 ) -> Result<Net> { 81 let mut num_queues = vu_cfg.num_queues; 82 83 let mut vu = 84 VhostUserHandle::connect_vhost_user(server, &vu_cfg.socket, num_queues as u64, false)?; 85 86 let (avail_features, acked_features, acked_protocol_features, vu_num_queues, config) = 87 if let Some(state) = state { 88 info!("Restoring vhost-user-net {}", id); 89 90 // The backend acknowledged features must not contain 91 // VIRTIO_NET_F_MAC since we don't expect the backend 92 // to handle it. 93 let backend_acked_features = state.acked_features & !(1 << VIRTIO_NET_F_MAC); 94 95 vu.set_protocol_features_vhost_user( 96 backend_acked_features, 97 state.acked_protocol_features, 98 )?; 99 100 // If the control queue feature has been negotiated, let's 101 // increase the number of queues. 102 if state.acked_features & (1 << VIRTIO_NET_F_CTRL_VQ) != 0 { 103 num_queues += 1; 104 } 105 106 ( 107 state.avail_features, 108 state.acked_features, 109 state.acked_protocol_features, 110 state.vu_num_queues, 111 state.config, 112 ) 113 } else { 114 // Filling device and vring features VMM supports. 115 let mut avail_features = 1 << VIRTIO_NET_F_CSUM 116 | 1 << VIRTIO_NET_F_GUEST_CSUM 117 | 1 << VIRTIO_NET_F_GUEST_TSO4 118 | 1 << VIRTIO_NET_F_GUEST_TSO6 119 | 1 << VIRTIO_NET_F_GUEST_ECN 120 | 1 << VIRTIO_NET_F_GUEST_UFO 121 | 1 << VIRTIO_NET_F_HOST_TSO4 122 | 1 << VIRTIO_NET_F_HOST_TSO6 123 | 1 << VIRTIO_NET_F_HOST_ECN 124 | 1 << VIRTIO_NET_F_HOST_UFO 125 | 1 << VIRTIO_NET_F_MRG_RXBUF 126 | 1 << VIRTIO_NET_F_CTRL_VQ 127 | 1 << VIRTIO_F_RING_EVENT_IDX 128 | 1 << VIRTIO_F_VERSION_1 129 | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(); 130 131 if mtu.is_some() { 132 avail_features |= 1u64 << VIRTIO_NET_F_MTU; 133 } 134 135 let mut config = VirtioNetConfig::default(); 136 build_net_config_space(&mut config, mac_addr, num_queues, mtu, &mut avail_features); 137 138 let avail_protocol_features = VhostUserProtocolFeatures::MQ 139 | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS 140 | VhostUserProtocolFeatures::REPLY_ACK 141 | VhostUserProtocolFeatures::INFLIGHT_SHMFD 142 | VhostUserProtocolFeatures::LOG_SHMFD; 143 144 let (mut acked_features, acked_protocol_features) = 145 vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?; 146 147 let backend_num_queues = 148 if acked_protocol_features & VhostUserProtocolFeatures::MQ.bits() != 0 { 149 vu.socket_handle() 150 .get_queue_num() 151 .map_err(Error::VhostUserGetQueueMaxNum)? 152 as usize 153 } else { 154 DEFAULT_QUEUE_NUMBER 155 }; 156 157 if num_queues > backend_num_queues { 158 error!("vhost-user-net requested too many queues ({}) since the backend only supports {}\n", 159 num_queues, backend_num_queues); 160 return Err(Error::BadQueueNum); 161 } 162 163 // If the control queue feature has been negotiated, let's increase 164 // the number of queues. 165 let vu_num_queues = num_queues; 166 if acked_features & (1 << VIRTIO_NET_F_CTRL_VQ) != 0 { 167 num_queues += 1; 168 } 169 170 // Make sure the virtio feature to set the MAC address is exposed to 171 // the guest, even if it hasn't been negotiated with the backend. 172 acked_features |= 1 << VIRTIO_NET_F_MAC; 173 174 ( 175 acked_features, 176 // If part of the available features that have been acked, 177 // the PROTOCOL_FEATURES bit must be already set through 178 // the VIRTIO acked features as we know the guest would 179 // never ack it, thus the feature would be lost. 180 acked_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits(), 181 acked_protocol_features, 182 vu_num_queues, 183 config, 184 ) 185 }; 186 187 Ok(Net { 188 id, 189 common: VirtioCommon { 190 device_type: VirtioDeviceType::Net as u32, 191 queue_sizes: vec![vu_cfg.queue_size; num_queues], 192 avail_features, 193 acked_features, 194 paused_sync: Some(Arc::new(Barrier::new(2))), 195 min_queues: DEFAULT_QUEUE_NUMBER as u16, 196 ..Default::default() 197 }, 198 vu_common: VhostUserCommon { 199 vu: Some(Arc::new(Mutex::new(vu))), 200 acked_protocol_features, 201 socket_path: vu_cfg.socket, 202 vu_num_queues, 203 server, 204 ..Default::default() 205 }, 206 config, 207 guest_memory: None, 208 ctrl_queue_epoll_thread: None, 209 epoll_thread: None, 210 seccomp_action, 211 exit_evt, 212 iommu, 213 }) 214 } 215 216 fn state(&self) -> State { 217 State { 218 avail_features: self.common.avail_features, 219 acked_features: self.common.acked_features, 220 config: self.config, 221 acked_protocol_features: self.vu_common.acked_protocol_features, 222 vu_num_queues: self.vu_common.vu_num_queues, 223 } 224 } 225 } 226 227 impl Drop for Net { 228 fn drop(&mut self) { 229 if let Some(kill_evt) = self.common.kill_evt.take() { 230 if let Err(e) = kill_evt.write(1) { 231 error!("failed to kill vhost-user-net: {:?}", e); 232 } 233 } 234 } 235 } 236 237 impl VirtioDevice for Net { 238 fn device_type(&self) -> u32 { 239 self.common.device_type 240 } 241 242 fn queue_max_sizes(&self) -> &[u16] { 243 &self.common.queue_sizes 244 } 245 246 fn features(&self) -> u64 { 247 let mut features = self.common.avail_features; 248 if self.iommu { 249 features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM; 250 } 251 features 252 } 253 254 fn ack_features(&mut self, value: u64) { 255 self.common.ack_features(value) 256 } 257 258 fn read_config(&self, offset: u64, data: &mut [u8]) { 259 self.read_config_from_slice(self.config.as_slice(), offset, data); 260 } 261 262 fn activate( 263 &mut self, 264 mem: GuestMemoryAtomic<GuestMemoryMmap>, 265 interrupt_cb: Arc<dyn VirtioInterrupt>, 266 mut queues: Vec<(usize, Queue, EventFd)>, 267 ) -> ActivateResult { 268 self.common.activate(&queues, &interrupt_cb)?; 269 self.guest_memory = Some(mem.clone()); 270 271 let num_queues = queues.len(); 272 let event_idx = self.common.feature_acked(VIRTIO_RING_F_EVENT_IDX.into()); 273 if self.common.feature_acked(VIRTIO_NET_F_CTRL_VQ.into()) && num_queues % 2 != 0 { 274 let ctrl_queue_index = num_queues - 1; 275 let (_, mut ctrl_queue, ctrl_queue_evt) = queues.remove(ctrl_queue_index); 276 277 ctrl_queue.set_event_idx(event_idx); 278 279 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 280 281 let mut ctrl_handler = NetCtrlEpollHandler { 282 mem: mem.clone(), 283 kill_evt, 284 pause_evt, 285 ctrl_q: CtrlQueue::new(Vec::new()), 286 queue: ctrl_queue, 287 queue_evt: ctrl_queue_evt, 288 access_platform: None, 289 interrupt_cb: interrupt_cb.clone(), 290 queue_index: ctrl_queue_index as u16, 291 }; 292 293 let paused = self.common.paused.clone(); 294 // Let's update the barrier as we need 1 for the control queue 295 // thread + 1 for the common vhost-user thread + 1 for the main 296 // thread signalling the pause. 297 self.common.paused_sync = Some(Arc::new(Barrier::new(3))); 298 let paused_sync = self.common.paused_sync.clone(); 299 300 let mut epoll_threads = Vec::new(); 301 spawn_virtio_thread( 302 &format!("{}_ctrl", &self.id), 303 &self.seccomp_action, 304 Thread::VirtioVhostNetCtl, 305 &mut epoll_threads, 306 &self.exit_evt, 307 move || ctrl_handler.run_ctrl(paused, paused_sync.unwrap()), 308 )?; 309 self.ctrl_queue_epoll_thread = Some(epoll_threads.remove(0)); 310 } 311 312 let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None; 313 314 // The backend acknowledged features must not contain VIRTIO_NET_F_MAC 315 // since we don't expect the backend to handle it. 316 let backend_acked_features = self.common.acked_features & !(1 << VIRTIO_NET_F_MAC); 317 318 // Run a dedicated thread for handling potential reconnections with 319 // the backend. 320 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 321 322 let mut handler = self.vu_common.activate( 323 mem, 324 queues, 325 interrupt_cb, 326 backend_acked_features, 327 slave_req_handler, 328 kill_evt, 329 pause_evt, 330 )?; 331 332 let paused = self.common.paused.clone(); 333 let paused_sync = self.common.paused_sync.clone(); 334 335 let mut epoll_threads = Vec::new(); 336 spawn_virtio_thread( 337 &self.id, 338 &self.seccomp_action, 339 Thread::VirtioVhostNet, 340 &mut epoll_threads, 341 &self.exit_evt, 342 move || handler.run(paused, paused_sync.unwrap()), 343 )?; 344 self.epoll_thread = Some(epoll_threads.remove(0)); 345 346 Ok(()) 347 } 348 349 fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 350 // We first must resume the virtio thread if it was paused. 351 if self.common.pause_evt.take().is_some() { 352 self.common.resume().ok()?; 353 } 354 355 if let Some(vu) = &self.vu_common.vu { 356 if let Err(e) = vu.lock().unwrap().reset_vhost_user() { 357 error!("Failed to reset vhost-user daemon: {:?}", e); 358 return None; 359 } 360 } 361 362 if let Some(kill_evt) = self.common.kill_evt.take() { 363 // Ignore the result because there is nothing we can do about it. 364 let _ = kill_evt.write(1); 365 } 366 367 event!("virtio-device", "reset", "id", &self.id); 368 369 // Return the interrupt 370 Some(self.common.interrupt_cb.take().unwrap()) 371 } 372 373 fn shutdown(&mut self) { 374 self.vu_common.shutdown(); 375 } 376 377 fn add_memory_region( 378 &mut self, 379 region: &Arc<GuestRegionMmap>, 380 ) -> std::result::Result<(), crate::Error> { 381 self.vu_common.add_memory_region(&self.guest_memory, region) 382 } 383 } 384 385 impl Pausable for Net { 386 fn pause(&mut self) -> result::Result<(), MigratableError> { 387 self.vu_common.pause()?; 388 self.common.pause() 389 } 390 391 fn resume(&mut self) -> result::Result<(), MigratableError> { 392 self.common.resume()?; 393 394 if let Some(epoll_thread) = &self.epoll_thread { 395 epoll_thread.thread().unpark(); 396 } 397 398 if let Some(ctrl_queue_epoll_thread) = &self.ctrl_queue_epoll_thread { 399 ctrl_queue_epoll_thread.thread().unpark(); 400 } 401 402 self.vu_common.resume() 403 } 404 } 405 406 impl Snapshottable for Net { 407 fn id(&self) -> String { 408 self.id.clone() 409 } 410 411 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 412 self.vu_common.snapshot(&self.id(), &self.state()) 413 } 414 } 415 impl Transportable for Net {} 416 417 impl Migratable for Net { 418 fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 419 self.vu_common.start_dirty_log(&self.guest_memory) 420 } 421 422 fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 423 self.vu_common.stop_dirty_log() 424 } 425 426 fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> { 427 self.vu_common.dirty_log(&self.guest_memory) 428 } 429 430 fn start_migration(&mut self) -> std::result::Result<(), MigratableError> { 431 self.vu_common.start_migration() 432 } 433 434 fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> { 435 self.vu_common 436 .complete_migration(self.common.kill_evt.take()) 437 } 438 } 439