Merge pull request #8516 from Apokleos/vsock-dev

move vsock device into device manager
This commit is contained in:
Greg Kurz
2023-12-05 11:28:37 +01:00
committed by GitHub
11 changed files with 152 additions and 61 deletions

View File

@@ -83,7 +83,8 @@ impl CloudHypervisorInner {
capabilities.set(
CapabilityBits::BlockDeviceSupport
| CapabilityBits::BlockDeviceHotplugSupport
| CapabilityBits::FsSharingSupport,
| CapabilityBits::FsSharingSupport
| CapabilityBits::HybridVsockSupport,
);
let (tx, rx) = channel(true);

View File

@@ -712,11 +712,14 @@ impl CloudHypervisorInner {
let flags = if guest_protection_is_tdx(self.guest_protection_to_use.clone()) {
// TDX does not permit the use of virtio-fs.
CapabilityBits::BlockDeviceSupport | CapabilityBits::BlockDeviceHotplugSupport
CapabilityBits::BlockDeviceSupport
| CapabilityBits::BlockDeviceHotplugSupport
| CapabilityBits::HybridVsockSupport
} else {
CapabilityBits::BlockDeviceSupport
| CapabilityBits::BlockDeviceHotplugSupport
| CapabilityBits::FsSharingSupport
| CapabilityBits::HybridVsockSupport
};
caps.set(flags);

View File

@@ -12,7 +12,7 @@ use tokio::sync::{Mutex, RwLock};
use crate::{
vhost_user_blk::VhostUserBlkDevice, BlockConfig, BlockDevice, HybridVsockDevice, Hypervisor,
NetworkDevice, ShareFsDevice, VfioDevice, VhostUserConfig, KATA_BLK_DEV_TYPE,
NetworkDevice, ShareFsDevice, VfioDevice, VhostUserConfig, VsockDevice, KATA_BLK_DEV_TYPE,
KATA_MMIO_BLK_DEV_TYPE, KATA_NVDIMM_DEV_TYPE, VIRTIO_BLOCK_MMIO, VIRTIO_BLOCK_PCI, VIRTIO_PMEM,
};
@@ -330,6 +330,10 @@ impl DeviceManager {
// No need to do find device for hybrid vsock device.
Arc::new(Mutex::new(HybridVsockDevice::new(&device_id, hvconfig)))
}
DeviceConfig::VsockCfg(_vconfig) => {
// No need to do find device for vsock device.
Arc::new(Mutex::new(VsockDevice::new(device_id.clone()).await?))
}
DeviceConfig::ShareFsCfg(config) => {
// Try to find the sharefs device. If found, just return matched device id.
if let Some(device_id_matched) =
@@ -346,9 +350,6 @@ impl DeviceManager {
Arc::new(Mutex::new(ShareFsDevice::new(&device_id, config)))
}
_ => {
return Err(anyhow!("invliad device type"));
}
};
// register device to devices

View File

@@ -84,16 +84,13 @@ impl Device for HybridVsockDevice {
}
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct VsockConfig {
/// A 32-bit Context Identifier (CID) used to identify the guest.
pub guest_cid: u32,
/// Vhost vsock fd. Hold to ensure CID is not used by other VM.
pub vhost_fd: File,
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct VsockDevice {
/// Unique identifier of the device
pub id: String,
@@ -121,46 +118,87 @@ const CID_RETRY_COUNT: u32 = 50;
impl VsockDevice {
pub async fn new(id: String) -> Result<Self> {
let vhost_fd = OpenOptions::new()
.read(true)
.write(true)
.open(VHOST_VSOCK_DEVICE)
let (guest_cid, _vhost_fd) = generate_vhost_vsock_cid()
.await
.context(format!(
"failed to open {}, try to run modprobe vhost_vsock.",
VHOST_VSOCK_DEVICE
))?;
let mut rng = rand::thread_rng();
.context("generate vhost vsock cid failed")?;
// Try 50 times to find a context ID that is not in use.
for _ in 0..CID_RETRY_COUNT {
// First usable CID above VMADDR_CID_HOST (see vsock(7))
let first_usable_cid = 3;
let rand_cid = rng.gen_range(first_usable_cid..=(u32::MAX));
let guest_cid =
unsafe { vhost_vsock_set_guest_cid(vhost_fd.as_raw_fd(), &(rand_cid as u64)) };
match guest_cid {
Ok(_) => {
return Ok(VsockDevice {
id,
config: VsockConfig {
guest_cid: rand_cid,
vhost_fd,
},
});
}
Err(nix::Error::EADDRINUSE) => {
// The CID is already in use. Try another one.
}
Err(err) => {
return Err(err).context("failed to set guest CID");
}
}
}
anyhow::bail!(
"failed to find a free vsock context ID after {} attempts",
CID_RETRY_COUNT
);
Ok(Self {
id,
config: VsockConfig { guest_cid },
})
}
}
#[async_trait]
impl Device for VsockDevice {
async fn attach(&mut self, h: &dyn hypervisor) -> Result<()> {
h.add_device(DeviceType::Vsock(self.clone()))
.await
.context("add vsock device.")?;
return Ok(());
}
async fn detach(&mut self, _h: &dyn hypervisor) -> Result<Option<u64>> {
// no need to do detach, just return Ok(None)
Ok(None)
}
async fn update(&mut self, _h: &dyn hypervisor) -> Result<()> {
// There's no need to do update for vsock device
Ok(())
}
async fn get_device_info(&self) -> DeviceType {
DeviceType::Vsock(self.clone())
}
async fn increase_attach_count(&mut self) -> Result<bool> {
// vsock devices will not be attached multiple times, Just return Ok(false)
Ok(false)
}
async fn decrease_attach_count(&mut self) -> Result<bool> {
// vsock devices will not be detached multiple times, Just return Ok(false)
Ok(false)
}
}
pub async fn generate_vhost_vsock_cid() -> Result<(u32, File)> {
let vhost_fd = OpenOptions::new()
.read(true)
.write(true)
.open(VHOST_VSOCK_DEVICE)
.await
.context(format!(
"failed to open {}, try to run modprobe vhost_vsock.",
VHOST_VSOCK_DEVICE
))?;
let mut rng = rand::thread_rng();
// Try 50 times to find a context ID that is not in use.
for _ in 0..CID_RETRY_COUNT {
// First usable CID above VMADDR_CID_HOST (see vsock(7))
let first_usable_cid = 3;
let rand_cid = rng.gen_range(first_usable_cid..=(u32::MAX));
let guest_cid =
unsafe { vhost_vsock_set_guest_cid(vhost_fd.as_raw_fd(), &(rand_cid as u64)) };
match guest_cid {
Ok(_) => return Ok((rand_cid, vhost_fd)),
Err(nix::Error::EADDRINUSE) => {
// The CID is already in use. Try another one.
continue;
}
Err(err) => {
return Err(err).context("failed to set guest CID");
}
};
}
anyhow::bail!(
"failed to find a free vsock context ID after {} attempts",
CID_RETRY_COUNT
);
}

View File

@@ -10,7 +10,7 @@ use crate::device::driver::vhost_user_blk::VhostUserBlkDevice;
use crate::{
BlockConfig, BlockDevice, HybridVsockConfig, HybridVsockDevice, Hypervisor as hypervisor,
NetworkConfig, NetworkDevice, ShareFsConfig, ShareFsDevice, VfioConfig, VfioDevice,
VhostUserConfig, VsockConfig,
VhostUserConfig, VsockConfig, VsockDevice,
};
use anyhow::Result;
use async_trait::async_trait;
@@ -38,6 +38,7 @@ pub enum DeviceType {
Network(NetworkDevice),
ShareFs(ShareFsDevice),
HybridVsock(HybridVsockDevice),
Vsock(VsockDevice),
}
impl fmt::Display for DeviceType {

View File

@@ -76,7 +76,8 @@ impl DragonballInner {
capabilities.set(
CapabilityBits::BlockDeviceSupport
| CapabilityBits::BlockDeviceHotplugSupport
| CapabilityBits::FsSharingSupport,
| CapabilityBits::FsSharingSupport
| CapabilityBits::HybridVsockSupport,
);
DragonballInner {
id: "".to_string(),

View File

@@ -67,6 +67,7 @@ impl DragonballInner {
DeviceType::ShareFs(sharefs) => self
.add_share_fs_device(&sharefs.config)
.context("add share fs device"),
DeviceType::Vsock(_) => todo!(),
}
}