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