Skip to content

设备直通与 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自定义后端

最佳实践

  1. 选择合适的设备类型

    • 通用场景使用 Virtio
    • 高性能场景使用 VFIO
    • 自定义后端使用 vhost-user
  2. 启用 IOMMU

    • VFIO 设备必须启用 IOMMU
    • Virtio 设备可选启用 IOMMU
  3. 限流配置

    • 块设备配置 rate limiter
    • 网络设备配置带宽限制
  4. 设备最小化

    • 只暴露必要的设备
    • 减少攻击面

下一步