mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +00:00
Add vhost-user vsock vmm
Add the vmm side for the vhost-user vsock device. BUG=b:179756331 TEST=Connect to vshd inside a VM with a vhost-user vsock device Change-Id: I332adbb6f8d6cfc8dff16375e93d946ecad2e84b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3153213 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Chirantan Ekbote <chirantan@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Keiichi Watanabe <keiichiw@chromium.org>
This commit is contained in:
parent
f08bdddf58
commit
84091e5331
6 changed files with 191 additions and 1 deletions
|
@ -10,6 +10,7 @@ mod gpu;
|
|||
mod handler;
|
||||
mod mac80211_hwsim;
|
||||
mod net;
|
||||
mod vsock;
|
||||
mod wl;
|
||||
mod worker;
|
||||
|
||||
|
@ -21,6 +22,7 @@ pub use self::gpu::*;
|
|||
pub use self::handler::VhostUserHandler;
|
||||
pub use self::mac80211_hwsim::*;
|
||||
pub use self::net::*;
|
||||
pub use self::vsock::*;
|
||||
pub use self::wl::*;
|
||||
|
||||
use remain::sorted;
|
||||
|
|
162
devices/src/virtio/vhost/user/vmm/vsock.rs
Normal file
162
devices/src/virtio/vhost/user/vmm/vsock.rs
Normal file
|
@ -0,0 +1,162 @@
|
|||
// Copyright 2021 The Chromium OS Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
use std::{cell::RefCell, os::unix::net::UnixStream, path::Path, thread};
|
||||
|
||||
use base::{error, Event, RawDescriptor};
|
||||
use cros_async::Executor;
|
||||
use data_model::Le64;
|
||||
use vm_memory::GuestMemory;
|
||||
use vmm_vhost::vhost_user::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
|
||||
|
||||
use crate::virtio::{
|
||||
vhost::{
|
||||
user::vmm::{handler::VhostUserHandler, worker::Worker, Error, Result},
|
||||
vsock,
|
||||
},
|
||||
Interrupt, Queue, VirtioDevice, TYPE_VSOCK, VIRTIO_F_VERSION_1,
|
||||
};
|
||||
|
||||
pub struct Vsock {
|
||||
kill_evt: Option<Event>,
|
||||
worker_thread: Option<thread::JoinHandle<Worker>>,
|
||||
handler: RefCell<VhostUserHandler>,
|
||||
queue_sizes: Vec<u16>,
|
||||
}
|
||||
|
||||
impl Vsock {
|
||||
pub fn new<P: AsRef<Path>>(base_features: u64, socket_path: P) -> Result<Vsock> {
|
||||
let socket = UnixStream::connect(socket_path).map_err(Error::SocketConnect)?;
|
||||
|
||||
let init_features = VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();
|
||||
let allow_features = init_features
|
||||
| base_features
|
||||
| 1 << VIRTIO_F_VERSION_1
|
||||
| 1 << virtio_sys::vhost::VIRTIO_RING_F_INDIRECT_DESC
|
||||
| 1 << virtio_sys::vhost::VIRTIO_RING_F_EVENT_IDX
|
||||
| 1 << virtio_sys::vhost::VIRTIO_F_NOTIFY_ON_EMPTY
|
||||
| 1 << virtio_sys::vhost::VHOST_F_LOG_ALL
|
||||
| 1 << virtio_sys::vhost::VIRTIO_F_ANY_LAYOUT;
|
||||
let allow_protocol_features =
|
||||
VhostUserProtocolFeatures::MQ | VhostUserProtocolFeatures::CONFIG;
|
||||
|
||||
let mut handler = VhostUserHandler::new_from_stream(
|
||||
socket,
|
||||
vsock::QUEUE_SIZES.len() as u64,
|
||||
allow_features,
|
||||
init_features,
|
||||
allow_protocol_features,
|
||||
)?;
|
||||
let queue_sizes = handler.queue_sizes(vsock::QUEUE_SIZE, vsock::QUEUE_SIZES.len())?;
|
||||
|
||||
Ok(Vsock {
|
||||
kill_evt: None,
|
||||
worker_thread: None,
|
||||
handler: RefCell::new(handler),
|
||||
queue_sizes,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Vsock {
|
||||
fn drop(&mut self) {
|
||||
if let Some(kill_evt) = self.kill_evt.take() {
|
||||
// Ignore the result because there is nothing we can do about it.
|
||||
let _ = kill_evt.write(1);
|
||||
}
|
||||
|
||||
if let Some(worker_thread) = self.worker_thread.take() {
|
||||
let _ = worker_thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioDevice for Vsock {
|
||||
fn keep_rds(&self) -> Vec<RawDescriptor> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn features(&self) -> u64 {
|
||||
self.handler.borrow().avail_features
|
||||
}
|
||||
|
||||
fn ack_features(&mut self, features: u64) {
|
||||
if let Err(e) = self.handler.borrow_mut().ack_features(features) {
|
||||
error!("failed to enable features 0x{:x}: {}", features, e);
|
||||
}
|
||||
}
|
||||
|
||||
fn device_type(&self) -> u32 {
|
||||
TYPE_VSOCK
|
||||
}
|
||||
|
||||
fn queue_max_sizes(&self) -> &[u16] {
|
||||
self.queue_sizes.as_slice()
|
||||
}
|
||||
|
||||
fn read_config(&self, offset: u64, data: &mut [u8]) {
|
||||
if let Err(e) = self.handler.borrow_mut().read_config::<Le64>(offset, data) {
|
||||
error!("failed to read config: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn activate(
|
||||
&mut self,
|
||||
mem: GuestMemory,
|
||||
interrupt: Interrupt,
|
||||
queues: Vec<Queue>,
|
||||
queue_evts: Vec<Event>,
|
||||
) {
|
||||
if let Err(e) = self
|
||||
.handler
|
||||
.borrow_mut()
|
||||
.activate(&mem, &interrupt, &queues, &queue_evts)
|
||||
{
|
||||
error!("failed to activate queues: {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("failed creating kill Event pair: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
self.kill_evt = Some(self_kill_evt);
|
||||
|
||||
let worker_result = thread::Builder::new()
|
||||
.name("vhost_user_vsock".to_string())
|
||||
.spawn(move || {
|
||||
let ex = Executor::new().expect("failed to create an executor");
|
||||
let mut worker = Worker {
|
||||
queues,
|
||||
mem,
|
||||
kill_evt,
|
||||
};
|
||||
if let Err(e) = worker.run(&ex, interrupt) {
|
||||
error!("failed to start a worker: {}", e);
|
||||
}
|
||||
worker
|
||||
});
|
||||
|
||||
match worker_result {
|
||||
Err(e) => {
|
||||
error!("failed to spawn virtio_vsock worker: {}", e);
|
||||
}
|
||||
Ok(join_handle) => {
|
||||
self.worker_thread = Some(join_handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reset(&mut self) -> bool {
|
||||
if let Err(e) = self.handler.borrow_mut().reset(self.queue_sizes.len()) {
|
||||
error!("Failed to reset vsock device: {}", e);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
|
@ -369,6 +369,7 @@ pub struct Config {
|
|||
pub vhost_user_gpu: Vec<VhostUserOption>,
|
||||
pub vhost_user_mac80211_hwsim: Option<VhostUserOption>,
|
||||
pub vhost_user_net: Vec<VhostUserOption>,
|
||||
pub vhost_user_vsock: Vec<VhostUserOption>,
|
||||
pub vhost_user_wl: Vec<VhostUserWlOption>,
|
||||
#[cfg(feature = "direct")]
|
||||
pub direct_pmio: Option<DirectIoOption>,
|
||||
|
@ -458,6 +459,7 @@ impl Default for Config {
|
|||
vhost_user_fs: Vec::new(),
|
||||
vhost_user_mac80211_hwsim: None,
|
||||
vhost_user_net: Vec::new(),
|
||||
vhost_user_vsock: Vec::new(),
|
||||
vhost_user_wl: Vec::new(),
|
||||
#[cfg(feature = "direct")]
|
||||
direct_pmio: None,
|
||||
|
|
|
@ -150,6 +150,7 @@ pub enum Error {
|
|||
VhostUserMac80211HwsimNew(VhostUserVmmError),
|
||||
VhostUserNetDeviceNew(VhostUserVmmError),
|
||||
VhostUserNetWithNetArgs,
|
||||
VhostUserVsockDeviceNew(VhostUserVmmError),
|
||||
VhostUserWlDeviceNew(VhostUserVmmError),
|
||||
VhostVsockDeviceNew(virtio::vhost::Error),
|
||||
VirtioPciDev(base::Error),
|
||||
|
@ -312,6 +313,9 @@ impl Display for Error {
|
|||
f,
|
||||
"vhost-user-net cannot be used with any of --host_ip, --netmask or --mac"
|
||||
),
|
||||
VhostUserVsockDeviceNew(e) => {
|
||||
write!(f, "failed to set up vhost-user vsock device: {}", e)
|
||||
}
|
||||
VhostUserWlDeviceNew(e) => {
|
||||
write!(f, "failed to set up vhost-user wl device: {}", e)
|
||||
}
|
||||
|
|
18
src/linux.rs
18
src/linux.rs
|
@ -34,7 +34,8 @@ use devices::vfio::{VfioCommonSetup, VfioCommonTrait};
|
|||
use devices::virtio::snd::cras_backend::Parameters as CrasSndParameters;
|
||||
use devices::virtio::vhost::user::vmm::{
|
||||
Block as VhostUserBlock, Console as VhostUserConsole, Fs as VhostUserFs,
|
||||
Mac80211Hwsim as VhostUserMac80211Hwsim, Net as VhostUserNet, Wl as VhostUserWl,
|
||||
Mac80211Hwsim as VhostUserMac80211Hwsim, Net as VhostUserNet, Vsock as VhostUserVsock,
|
||||
Wl as VhostUserWl,
|
||||
};
|
||||
use devices::virtio::{self, Console, VirtioDevice};
|
||||
#[cfg(feature = "gpu")]
|
||||
|
@ -646,6 +647,17 @@ fn create_vhost_user_net_device(cfg: &Config, opt: &VhostUserOption) -> DeviceRe
|
|||
})
|
||||
}
|
||||
|
||||
fn create_vhost_user_vsock_device(cfg: &Config, opt: &VhostUserOption) -> DeviceResult {
|
||||
let dev = VhostUserVsock::new(virtio::base_features(cfg.protected_vm), &opt.socket)
|
||||
.map_err(Error::VhostUserVsockDeviceNew)?;
|
||||
|
||||
Ok(VirtioDeviceStub {
|
||||
dev: Box::new(dev),
|
||||
// no sandbox here because virtqueue handling is exported to a different process.
|
||||
jail: None,
|
||||
})
|
||||
}
|
||||
|
||||
fn create_vhost_user_wl_device(cfg: &Config, opt: &VhostUserWlOption) -> DeviceResult {
|
||||
// The crosvm wl device expects us to connect the tube before it will accept a vhost-user
|
||||
// connection.
|
||||
|
@ -1353,6 +1365,10 @@ fn create_virtio_devices(
|
|||
devs.push(create_vhost_user_net_device(cfg, net)?);
|
||||
}
|
||||
|
||||
for vsock in &cfg.vhost_user_vsock {
|
||||
devs.push(create_vhost_user_vsock_device(cfg, vsock)?);
|
||||
}
|
||||
|
||||
for opt in &cfg.vhost_user_wl {
|
||||
devs.push(create_vhost_user_wl_device(cfg, opt)?);
|
||||
}
|
||||
|
|
|
@ -1861,6 +1861,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument::
|
|||
"vhost-user-net" => cfg.vhost_user_net.push(VhostUserOption {
|
||||
socket: PathBuf::from(value.unwrap()),
|
||||
}),
|
||||
"vhost-user-vsock" => cfg.vhost_user_vsock.push(VhostUserOption {
|
||||
socket: PathBuf::from(value.unwrap()),
|
||||
}),
|
||||
"vhost-user-wl" => {
|
||||
let mut components = value.unwrap().splitn(2, ":");
|
||||
let socket = components.next().map(PathBuf::from).ok_or_else(|| {
|
||||
|
@ -2216,6 +2219,7 @@ iommu=on|off - indicates whether to enable virtio IOMMU for this device"),
|
|||
Argument::value("vhost-user-gpu", "SOCKET_PATH", "Paths to a vhost-user socket for gpu"),
|
||||
Argument::value("vhost-user-mac80211-hwsim", "SOCKET_PATH", "Path to a socket for vhost-user mac80211_hwsim"),
|
||||
Argument::value("vhost-user-net", "SOCKET_PATH", "Path to a socket for vhost-user net"),
|
||||
Argument::value("vhost-user-vsock", "SOCKET_PATH", "Path to a socket for vhost-user vsock"),
|
||||
Argument::value("vhost-user-wl", "SOCKET_PATH:TUBE_PATH", "Paths to a vhost-user socket for wayland and a Tube socket for additional wayland-specific messages"),
|
||||
Argument::value("vhost-user-fs", "SOCKET_PATH:TAG",
|
||||
"Path to a socket path for vhost-user fs, and tag for the shared dir"),
|
||||
|
|
Loading…
Reference in a new issue