设备直通与 Virtio
概述
Cube Hypervisor 支持两种设备模型:Virtio 半虚拟化设备和 VFIO 设备直通。Virtio 提供兼容性和灵活性,VFIO 提供接近原生的性能。
Virtio 设备
Virtio 协议
Virtio 是一种标准化的半虚拟化设备协议,通过 virtqueue 实现高效的数据传输:
Virtqueue 结构
rust
// vm-virtio/src/queue.rs
pub struct Queue {
pub max_size: u16,
pub size: u16,
pub ready: bool,
pub desc_table: GuestAddress,
pub avail_ring: GuestAddress,
pub used_ring: GuestAddress,
pub next_avail: Wrapping<u16>,
pub next_used: Wrapping<u16>,
pub iommu_mapping: Option<Arc<dyn ExternalDmaMapping>>,
}
pub struct Descriptor {
pub addr: u64,
pub len: u32,
pub flags: u16,
pub next: u16,
}Virtio 块设备
rust
// virtio-devices/src/block.rs
pub struct Block {
common: VirtioCommon,
disk_image: Box<dyn DiskFile>,
disk_path: PathBuf,
rate_limiter: Option<RateLimiter>,
read_only: bool,
serial: Vec<u8>,
config: VirtioBlockConfig,
}
impl VirtioDevice for Block {
fn device_type(&self) -> VirtioDeviceType {
VirtioDeviceType::Block
}
fn activate(&mut self, mem: GuestMemoryAtomic, ...) -> ActivateResult {
// 启动 epoll 事件循环
let handler = BlockEpollHandler {
disk_image: self.disk_image.clone(),
mem,
queue,
rate_limiter: self.rate_limiter.take(),
// ...
};
thread::spawn(move || {
handler.run(paused, paused_sync);
});
Ok(())
}
}Virtio 网络设备
rust
// virtio-devices/src/net.rs
pub struct Net {
common: VirtioCommon,
net: NetQueuePair,
ctrl_queue: Option<CtrlQueue>,
taps: Vec<Tap>,
config: VirtioNetConfig,
}
impl VirtioDevice for Net {
fn activate(&mut self, mem: GuestMemoryAtomic, ...) -> ActivateResult {
// 配置 TAP 设备
for (i, tap) in self.taps.iter_mut().enumerate() {
tap.enable()?;
tap.set_offload(virtio_features_to_tap_offload(self.common.acked_features))?;
}
// 启动数据路径
// ...
Ok(())
}
}Virtio 文件系统
rust
// virtio-devices/src/fs.rs
pub struct Fs {
common: VirtioCommon,
fs: PassthroughFs,
cache: CachePolicy,
thread_pool_size: usize,
xattr: XattrMap,
config: VirtioFsConfig,
}
impl VirtioDevice for Fs {
fn activate(&mut self, mem: GuestMemoryAtomic, ...) -> ActivateResult {
// 启动 virtiofsd 处理线程
for _ in 0..self.thread_pool_size {
let handler = FsEpollHandler {
fs: self.fs.clone(),
mem: mem.clone(),
// ...
};
thread::spawn(move || {
handler.run();
});
}
Ok(())
}
}VFIO 设备直通
VFIO 原理
VFIO(Virtual Function I/O)允许将物理设备直接分配给虚拟机:
IOMMU 隔离
rust
// pci/src/vfio.rs
pub struct VfioPciDevice {
device: VfioDevice,
container: Arc<VfioContainer>,
vfio_device_fd: Arc<VfioDeviceFd>,
configuration: PciConfiguration,
bars: Vec<PciBar>,
dma_mapping: Option<Arc<dyn ExternalDmaMapping>>,
}
impl VfioPciDevice {
pub fn new(
device: VfioDevice,
container: Arc<VfioContainer>,
dma_mapping: Option<Arc<dyn ExternalDmaMapping>>,
) -> Result<Self> {
// 设置 IOMMU DMA 映射
if let Some(mapping) = &dma_mapping {
container.set_dma_map(mapping)?;
}
Ok(Self {
device,
container,
// ...
})
}
}DMA 映射
rust
// vm-device/src/dma_mapping/vfio.rs
pub struct VfioDmaMapping {
container: Arc<VfioContainer>,
memory: GuestMemoryAtomic,
}
impl ExternalDmaMapping for VfioDmaMapping {
fn map(&self, iova: u64, gpa: u64, size: u64) -> Result<()> {
// 将 Guest 物理地址映射到 IOVA
self.container.vfio_dma_map(iova, gpa, size)?;
Ok(())
}
fn unmap(&self, iova: u64, size: u64) -> Result<()> {
// 取消映射
self.container.vfio_dma_unmap(iova, size)?;
Ok(())
}
}设备管理
DeviceManager
DeviceManager 负责管理所有设备的生命周期:
rust
// vmm/src/device_manager.rs
pub struct DeviceManager {
// 设备列表
devices: HashMap<String, Arc<Mutex<dyn BusDevice>>>,
// Virtio 设备
virtio_devices: Vec<Arc<Mutex<dyn VirtioDevice>>>,
// PCI 设备
pci_devices: Vec<Arc<Mutex<dyn PciDevice>>>,
// 中断管理器
interrupt_manager: Arc<dyn InterruptManager>,
// 内存管理器
memory_manager: Arc<Mutex<MemoryManager>>,
// 总线
io_bus: Bus,
mmio_bus: Bus,
}设备创建流程
vhost-user
vhost-user 允许将设备后端运行在独立进程中:
vhost-user 块设备
rust
// virtio-devices/src/vhost_user/blk.rs
pub struct VhostUserBlk {
common: VirtioCommon,
vu: VhostUserHandle,
config: VhostUserConfig,
acked_protocol_features: u64,
}
impl VirtioDevice for VhostUserBlk {
fn activate(&mut self, mem: GuestMemoryAtomic, ...) -> ActivateResult {
// 设置 vhost-user 协议
self.vu.set_owner()?;
self.vu.get_features()?;
self.vu.set_features(self.common.acked_features)?;
// 设置 virtqueue
for (i, queue) in self.common.queues.iter().enumerate() {
self.vu.set_vring_num(i, queue.size)?;
self.vu.set_vring_base(i, queue.next_avail)?;
self.vu.set_vring_call(i, &queue.eventfd)?;
self.vu.set_vring_kick(i, &queue.eventfd)?;
}
Ok(())
}
}设备性能对比
| 设备类型 | 吞吐量 | 延迟 | CPU 开销 | 适用场景 |
|---|---|---|---|---|
| Virtio-blk | 高 | 低 | 中 | 通用块设备 |
| Virtio-net | 高 | 低 | 中 | 通用网络 |
| VFIO NVMe | 极高 | 极低 | 极低 | 高性能存储 |
| VFIO NIC | 极高 | 极低 | 极低 | 高性能网络 |
| vhost-user | 高 | 低 | 低 | 自定义后端 |
最佳实践
选择合适的设备类型
- 通用场景使用 Virtio
- 高性能场景使用 VFIO
- 自定义后端使用 vhost-user
启用 IOMMU
- VFIO 设备必须启用 IOMMU
- Virtio 设备可选启用 IOMMU
限流配置
- 块设备配置 rate limiter
- 网络设备配置带宽限制
设备最小化
- 只暴露必要的设备
- 减少攻击面
下一步
- 了解 内存管理
- 深入 Virtio 设备源码