1 // Copyright 2017 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::collections::BTreeMap; 6 use std::fs::OpenOptions; 7 use std::os::unix::prelude::OpenOptionsExt; 8 9 use anyhow::anyhow; 10 use anyhow::Context; 11 use base::error; 12 use base::open_file_or_duplicate; 13 use base::warn; 14 use base::AsRawDescriptor; 15 use base::Event; 16 use base::RawDescriptor; 17 use base::WorkerThread; 18 use data_model::Le64; 19 use serde::Deserialize; 20 use serde::Serialize; 21 use snapshot::AnySnapshot; 22 use vhost::Vhost; 23 use vhost::Vsock as VhostVsockHandle; 24 use vm_memory::GuestMemory; 25 use zerocopy::IntoBytes; 26 27 use super::worker::VringBase; 28 use super::worker::Worker; 29 use super::Error; 30 use super::Result; 31 use crate::virtio::copy_config; 32 use crate::virtio::device_constants::vsock::NUM_QUEUES; 33 use crate::virtio::vsock::VsockConfig; 34 use crate::virtio::DeviceType; 35 use crate::virtio::Interrupt; 36 use crate::virtio::Queue; 37 use crate::virtio::VirtioDevice; 38 39 const QUEUE_SIZE: u16 = 256; 40 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES]; 41 42 pub struct Vsock { 43 worker_thread: Option<WorkerThread<Worker<VhostVsockHandle>>>, 44 vhost_handle: Option<VhostVsockHandle>, 45 cid: u64, 46 interrupts: Option<Vec<Event>>, 47 avail_features: u64, 48 acked_features: u64, 49 // vrings_base states: 50 // None - device was just created or is running. 51 // Some - device was put to sleep after running or was restored. 52 vrings_base: Option<Vec<VringBase>>, 53 // Some iff the device is active and awake. 54 event_queue: Option<Queue>, 55 // If true, we should send a TRANSPORT_RESET event to the guest at the next opportunity. 56 needs_transport_reset: bool, 57 } 58 59 #[derive(Serialize, Deserialize)] 60 struct VsockSnapshot { 61 cid: u64, 62 avail_features: u64, 63 acked_features: u64, 64 vrings_base: Vec<VringBase>, 65 } 66 67 impl Vsock { 68 /// Create a new virtio-vsock device with the given VM cid. new(base_features: u64, vsock_config: &VsockConfig) -> anyhow::Result<Vsock>69 pub fn new(base_features: u64, vsock_config: &VsockConfig) -> anyhow::Result<Vsock> { 70 let device_file = open_file_or_duplicate( 71 &vsock_config.vhost_device, 72 OpenOptions::new() 73 .read(true) 74 .write(true) 75 .custom_flags(libc::O_CLOEXEC | libc::O_NONBLOCK), 76 ) 77 .with_context(|| { 78 format!( 79 "failed to open virtual socket device {}", 80 vsock_config.vhost_device.display(), 81 ) 82 })?; 83 84 let handle = VhostVsockHandle::new(device_file); 85 86 let avail_features = base_features; 87 88 let mut interrupts = Vec::new(); 89 for _ in 0..NUM_QUEUES { 90 interrupts.push(Event::new().map_err(Error::VhostIrqCreate)?); 91 } 92 93 Ok(Vsock { 94 worker_thread: None, 95 vhost_handle: Some(handle), 96 cid: vsock_config.cid, 97 interrupts: Some(interrupts), 98 avail_features, 99 acked_features: 0, 100 vrings_base: None, 101 event_queue: None, 102 needs_transport_reset: false, 103 }) 104 } 105 new_for_testing(cid: u64, features: u64) -> Vsock106 pub fn new_for_testing(cid: u64, features: u64) -> Vsock { 107 Vsock { 108 worker_thread: None, 109 vhost_handle: None, 110 cid, 111 interrupts: None, 112 avail_features: features, 113 acked_features: 0, 114 vrings_base: None, 115 event_queue: None, 116 needs_transport_reset: false, 117 } 118 } 119 acked_features(&self) -> u64120 pub fn acked_features(&self) -> u64 { 121 self.acked_features 122 } 123 } 124 125 impl VirtioDevice for Vsock { keep_rds(&self) -> Vec<RawDescriptor>126 fn keep_rds(&self) -> Vec<RawDescriptor> { 127 let mut keep_rds = Vec::new(); 128 129 if let Some(handle) = &self.vhost_handle { 130 keep_rds.push(handle.as_raw_descriptor()); 131 } 132 133 if let Some(interrupt) = &self.interrupts { 134 for vhost_int in interrupt.iter() { 135 keep_rds.push(vhost_int.as_raw_descriptor()); 136 } 137 } 138 139 keep_rds 140 } 141 device_type(&self) -> DeviceType142 fn device_type(&self) -> DeviceType { 143 DeviceType::Vsock 144 } 145 queue_max_sizes(&self) -> &[u16]146 fn queue_max_sizes(&self) -> &[u16] { 147 QUEUE_SIZES 148 } 149 features(&self) -> u64150 fn features(&self) -> u64 { 151 self.avail_features 152 } 153 read_config(&self, offset: u64, data: &mut [u8])154 fn read_config(&self, offset: u64, data: &mut [u8]) { 155 let cid = Le64::from(self.cid); 156 copy_config(data, 0, cid.as_bytes(), offset); 157 } 158 ack_features(&mut self, value: u64)159 fn ack_features(&mut self, value: u64) { 160 let mut v = value; 161 162 // Check if the guest is ACK'ing a feature that we didn't claim to have. 163 let unrequested_features = v & !self.avail_features; 164 if unrequested_features != 0 { 165 warn!("vsock: virtio-vsock got unknown feature ack: {:x}", v); 166 167 // Don't count these features as acked. 168 v &= !unrequested_features; 169 } 170 self.acked_features |= v; 171 } 172 activate( &mut self, mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>173 fn activate( 174 &mut self, 175 mem: GuestMemory, 176 interrupt: Interrupt, 177 mut queues: BTreeMap<usize, Queue>, 178 ) -> anyhow::Result<()> { 179 if queues.len() != NUM_QUEUES { 180 return Err(anyhow!( 181 "net: expected {} queues, got {}", 182 NUM_QUEUES, 183 queues.len() 184 )); 185 } 186 187 let vhost_handle = self.vhost_handle.take().context("missing vhost_handle")?; 188 let interrupts = self.interrupts.take().context("missing interrupts")?; 189 let acked_features = self.acked_features; 190 let cid = self.cid; 191 192 // The third vq is an event-only vq that is not handled by the vhost 193 // subsystem (but still needs to exist). Split it off here. 194 let mut event_queue = queues.remove(&2).unwrap(); 195 // Send TRANSPORT_RESET event if needed. 196 if self.needs_transport_reset { 197 self.needs_transport_reset = false; 198 199 // We assume the event queue is non-empty. This should be OK for existing use cases 200 // because we expect the guest vsock driver to be initialized at the time of snapshot 201 // and this is only the event we ever write to the queue. 202 // 203 // If that assumption becomes invalid, we could integrate this logic into the worker 204 // thread's event loop so that it can wait for space in the queue. 205 let mut avail_desc = event_queue 206 .pop() 207 .expect("event queue is empty, can't send transport reset event"); 208 let transport_reset = virtio_sys::virtio_vsock::virtio_vsock_event{ 209 id: virtio_sys::virtio_vsock::virtio_vsock_event_id_VIRTIO_VSOCK_EVENT_TRANSPORT_RESET.into(), 210 }; 211 avail_desc 212 .writer 213 .write_obj(transport_reset) 214 .expect("failed to write transport reset event"); 215 let len = avail_desc.writer.bytes_written() as u32; 216 event_queue.add_used(avail_desc, len); 217 event_queue.trigger_interrupt(); 218 } 219 self.event_queue = Some(event_queue); 220 221 let mut worker = Worker::new( 222 queues, 223 vhost_handle, 224 interrupts, 225 interrupt, 226 acked_features, 227 None, 228 ); 229 let activate_vqs = |handle: &VhostVsockHandle| -> Result<()> { 230 handle.set_cid(cid).map_err(Error::VhostVsockSetCid)?; 231 handle.start().map_err(Error::VhostVsockStart)?; 232 Ok(()) 233 }; 234 worker 235 .init(mem, QUEUE_SIZES, activate_vqs, self.vrings_base.take()) 236 .context("vsock worker init exited with error")?; 237 238 self.worker_thread = Some(WorkerThread::start("vhost_vsock", move |kill_evt| { 239 let cleanup_vqs = |_handle: &VhostVsockHandle| -> Result<()> { Ok(()) }; 240 let result = worker.run(cleanup_vqs, kill_evt); 241 if let Err(e) = result { 242 error!("vsock worker thread exited with error: {:?}", e); 243 } 244 worker 245 })); 246 247 Ok(()) 248 } 249 reset(&mut self) -> anyhow::Result<()>250 fn reset(&mut self) -> anyhow::Result<()> { 251 if let Some(worker_thread) = self.worker_thread.take() { 252 let worker = worker_thread.stop(); 253 worker 254 .vhost_handle 255 .stop() 256 .context("failed to stop vrings")?; 257 // Call get_vring_base to stop the queues. 258 for (pos, _) in worker.queues.iter() { 259 worker 260 .vhost_handle 261 .get_vring_base(*pos) 262 .context("get_vring_base failed")?; 263 } 264 265 self.vhost_handle = Some(worker.vhost_handle); 266 self.interrupts = Some(worker.vhost_interrupt); 267 } 268 self.acked_features = 0; 269 self.vrings_base = None; 270 self.event_queue = None; 271 self.needs_transport_reset = false; 272 Ok(()) 273 } 274 on_device_sandboxed(&mut self)275 fn on_device_sandboxed(&mut self) { 276 // ignore the error but to log the error. We don't need to do 277 // anything here because when activate, the other vhost set up 278 // will be failed to stop the activate thread. 279 if let Some(vhost_handle) = &self.vhost_handle { 280 match vhost_handle.set_owner() { 281 Ok(_) => {} 282 Err(e) => error!("{}: failed to set owner: {:?}", self.debug_label(), e), 283 } 284 } 285 } 286 virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>287 fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> { 288 if let Some(worker_thread) = self.worker_thread.take() { 289 let worker = worker_thread.stop(); 290 self.interrupts = Some(worker.vhost_interrupt); 291 worker 292 .vhost_handle 293 .stop() 294 .context("failed to stop vrings")?; 295 let mut queues: BTreeMap<usize, Queue> = worker.queues; 296 let mut vrings_base = Vec::new(); 297 for (pos, _) in queues.iter() { 298 let vring_base = VringBase { 299 index: *pos, 300 base: worker.vhost_handle.get_vring_base(*pos)?, 301 }; 302 vrings_base.push(vring_base); 303 } 304 self.vrings_base = Some(vrings_base); 305 self.vhost_handle = Some(worker.vhost_handle); 306 queues.insert( 307 2, 308 self.event_queue.take().expect("Vsock event queue missing"), 309 ); 310 return Ok(Some(BTreeMap::from_iter(queues))); 311 } 312 Ok(None) 313 } 314 virtio_wake( &mut self, device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>315 fn virtio_wake( 316 &mut self, 317 device_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, 318 ) -> anyhow::Result<()> { 319 match device_state { 320 None => Ok(()), 321 Some((mem, interrupt, queues)) => { 322 // TODO: activate is just what we want at the moment, but we should probably move 323 // it into a "start workers" function to make it obvious that it isn't strictly 324 // used for activate events. 325 self.activate(mem, interrupt, queues)?; 326 Ok(()) 327 } 328 } 329 } 330 virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot>331 fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> { 332 let vrings_base = self.vrings_base.clone().unwrap_or_default(); 333 AnySnapshot::to_any(VsockSnapshot { 334 // `cid` and `avail_features` are snapshot as a safeguard. Upon restore, validate 335 // cid and avail_features in the current vsock match the previously snapshot vsock. 336 cid: self.cid, 337 avail_features: self.avail_features, 338 acked_features: self.acked_features, 339 vrings_base, 340 }) 341 .context("failed to snapshot virtio console") 342 } 343 virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>344 fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> { 345 let deser: VsockSnapshot = 346 AnySnapshot::from_any(data).context("failed to deserialize virtio vsock")?; 347 anyhow::ensure!( 348 self.cid == deser.cid, 349 "Virtio vsock incorrect cid for restore:\n Expected: {}, Actual: {}", 350 self.cid, 351 deser.cid, 352 ); 353 anyhow::ensure!( 354 self.avail_features == deser.avail_features, 355 "Virtio vsock incorrect avail features for restore:\n Expected: {}, Actual: {}", 356 self.avail_features, 357 deser.avail_features, 358 ); 359 self.acked_features = deser.acked_features; 360 self.vrings_base = Some(deser.vrings_base); 361 // Send the TRANSPORT_RESET on next wake so that the guest knows that its existing vsock 362 // connections are broken. 363 self.needs_transport_reset = true; 364 Ok(()) 365 } 366 } 367 368 #[cfg(test)] 369 mod tests { 370 use std::convert::TryInto; 371 372 use super::*; 373 374 #[test] ack_features()375 fn ack_features() { 376 let cid = 5; 377 let features: u64 = (1 << 20) | (1 << 49) | (1 << 2) | (1 << 19); 378 let mut acked_features: u64 = 0; 379 let mut unavailable_features: u64 = 0; 380 381 let mut vsock = Vsock::new_for_testing(cid, features); 382 assert_eq!(acked_features, vsock.acked_features()); 383 384 acked_features |= 1 << 2; 385 vsock.ack_features(acked_features); 386 assert_eq!(acked_features, vsock.acked_features()); 387 388 acked_features |= 1 << 49; 389 vsock.ack_features(acked_features); 390 assert_eq!(acked_features, vsock.acked_features()); 391 392 acked_features |= 1 << 60; 393 unavailable_features |= 1 << 60; 394 vsock.ack_features(acked_features); 395 assert_eq!( 396 acked_features & !unavailable_features, 397 vsock.acked_features() 398 ); 399 400 acked_features |= 1 << 1; 401 unavailable_features |= 1 << 1; 402 vsock.ack_features(acked_features); 403 assert_eq!( 404 acked_features & !unavailable_features, 405 vsock.acked_features() 406 ); 407 } 408 409 #[test] read_config()410 fn read_config() { 411 let cid = 0xfca9a559fdcb9756; 412 let vsock = Vsock::new_for_testing(cid, 0); 413 414 let mut buf = [0u8; 8]; 415 vsock.read_config(0, &mut buf); 416 assert_eq!(cid, u64::from_le_bytes(buf)); 417 418 vsock.read_config(0, &mut buf[..4]); 419 assert_eq!( 420 (cid & 0xffffffff) as u32, 421 u32::from_le_bytes(buf[..4].try_into().unwrap()) 422 ); 423 424 vsock.read_config(4, &mut buf[..4]); 425 assert_eq!( 426 (cid >> 32) as u32, 427 u32::from_le_bytes(buf[..4].try_into().unwrap()) 428 ); 429 430 let data: [u8; 8] = [8, 226, 5, 46, 159, 59, 89, 77]; 431 buf.copy_from_slice(&data); 432 433 vsock.read_config(12, &mut buf); 434 assert_eq!(&buf, &data); 435 } 436 437 #[test] features()438 fn features() { 439 let cid = 5; 440 let features: u64 = 0xfc195ae8db88cff9; 441 442 let vsock = Vsock::new_for_testing(cid, features); 443 assert_eq!(features, vsock.features()); 444 } 445 } 446