云计算国产化之路 vnc登录 文件系统直通(virtio-9p) 扩展qemu接口 gpg WARNING 珍藏博客 虚拟内存情况dommemstat分析 免密码自动登录脚本 Linux网桥 测试网段IP占用情况 Linux 进程状态 systemc强制依赖 调试openstack ut uefi p2v 重做ubuntu内核 virsh创建虚拟机简介 virtio IO路径 虚拟化层升级后磁盘无法卸载卷 vmtouch使用 Taint flags 主机和虚拟机文件共享处理的几种方法 kvm分析工具 kvm中对磁盘的io cache 虚拟化不同导致的guestos中软件安装差异(未解决) 设备直通(PCI Assignment)到底是咋整的 virtio到底是咋整的 内核启动参数 虚拟化实时性提升(零)之配置步骤 中断虚拟化(pic)到底是咋整的 中断虚拟化(apic)到底是咋整的 Raid卡配置丢失导致服务器无法启动 tainted kernels cpu stuck for 23s问题分析 虚拟化实时性提升(一)之hostOS切换为强实时系统 内存虚拟化到底是咋整的 qemu-kvm中vcpu虚拟化到底是咋整的 风河虚拟化技术点分析 使用qga的好处 qemu迁移代码分析 虚拟机串口配置及其导出到主机pts和console.log System-based I/O vs. Raw I/O 虚拟机使用Hugepage(大页) 硬件辅助分页(hardware assisted paging) 修改centos7默认启动项目 virtio的工作流程——kernel中virtio-pci初始化(2) virtio的工作流程——qemu中virtio-backend初始化(1) qmp ceilometer取不到memory.usage指标 Virtio-Balloon超详细分析 slabtop输出 虚拟机磁盘cache导致的host os kernel崩溃 虚拟机cpu和memory性能优化测评 PCI配置空间(PCI Configuration Space) centos下网卡设备直通(VT-dpci passthrough)遇到的问题及其解决思路 libguestfs详解 yum卸载软件包及其依赖 通过原始Centos ISO来定制自己的ISO centos下网卡设备直通(VT-d,pci passthrough) (占位符)window虚拟机中拔盘如何通知到libvirt和qemu后端的 cirrus漏洞分析CVE-2017-2615 XSA-208 qcow2随笔 控制寄存器概览 ceilometer对接postgresql 解压initrd和vmlinuz qemu guest agent验证 QEMU升级指南(待续) ubuntu中kdump的配置 qemu(2.3)接口梳理 热迁移导致的FC存储场景下的multipath卷残留问题分析 virsh命令(4)secret,snapshot,pool,volume部分 virsh命令(3)之interface,filter,network virsh命令(2)monitor,host,nodedev部分 virsh命令(1)之domain部分 QEMU内存管理之FlatView模型(QEMU2.0.0) ovirt基于sanock的高可用(主机粒度HA) Sanlock防脑裂场景功能测试用例 gnocchi配置及与ceilometer对接指南 make patch for libvirt in centos centos使用sanlock指导 高可用nfs资料 ubuntu14中使用sanlock指导 LVM操作指南 sanlock相关功能验证流程汇总 make patch for libvirt in ubuntu libvirt.so.0-version `LIBVIRT_PRIVATE_1.2.7' not found gdb debug libvirt 基于ubuntu社区源码包编译libvirt compile libvirt(centos) No PCI buses available nfs lead to Linux halt nfs install and config anti-virus for cloud platform nova fetch image from glance(something about _base) token auth process ovs入门指南 virt software anti-virus something about ceilometer disk sample context interview questions openstack vm injection openstack Restful and RPC murano 概览 创建虚拟机流程(compute节点)之网络创建 创建虚拟机流程之compute_api之虚拟机实例填充之配额检测 创建虚拟机流程之compute_api之基本参数生成 创建虚拟机流程之compute_api 创建虚拟机流程(主) 创建虚拟机之image 创建虚拟机流程之准备网桥 创建虚拟机流程之virt 创建虚拟机流程之compute节点 CI/CD研发流程之工程创建 CI/CD研发流程之代码合入 CI/CD研发流程之UT(单元测试) 向openstack社区合入代码记 openstack/ceilometer/gnocchi杂谈 影子页表原理 mem_add(exec.c) qemu编译安装调试 openstack/ceilometer/gnocchi之Grafana简介 openstack wiki etcd openstack计量ceilometer openstack计费cloudKitty enventlet backdoor USB 安装VMWARE ESX pycharm设置指南 无法执行modprobe -a kvm-intel解决办法 QEMU配置项 网络不通小记 libvirt之XML(虚拟机定义文件) openstack-horizon 证书认证 ceilometer与ceph对接 openstack定时任务剖析(TODO) 服务器重启后mongodb进程无法启动 ubuntu14下新增openstack服务到service的导引 ERROR 1045(28000)-数据库连不上 Python两个内置函数—locals和globals unknown exit, hardware reason 31

设备直通(PCI Assignment)到底是咋整的

2017年06月05日

背景

IO虚拟化的三板斧:
1.全模拟;2.virtio驱动半虚拟化;3.设备直通

本文主要聚焦设备直通,重点阐述原理
至于上述三种的优缺点,如何直通等入门级资料请自行谷歌

本人这篇博文中讲述了如何进行pci网卡的直通
这篇博文讲述了直通过程中遇到的问题,及其解决思路

一句话总结

将设备从主机的总线上拿下来,挂到模拟出来的虚拟机总线上去。
这其中需要解决两个问题: 1.数据传输中,即dma时,设备如何直接访问到guestos内的地址
2.中断过程中,设备的中断如何直达guestos

以上是VT_到解决的主要两个问题,它通过北桥(现在叫MCH)中内置的硬件借助于iommu,dmar及其重构msi结构实现了DMA虚拟化和中断虚拟化。

(VT-d interrupt-remapping重新定义MSI的格式,它依旧是一个DMA写请求的形式,不过其中不是目标内存地址,而是一个消息ID,通过维护一个表结构,硬件可以通过消息ID区分不同的虚拟机)

原理

设备直通可以通过kvm和vfio两种方式
kvm方式是qemu调用kvm实现设备的直通,是一种传统方式
vfio是将内核态的iommu通过接口暴露给用户态,实现的设备直通,qemu调用vfio,vfio再调用iommu等实现直通,具体vfio参考这里

kvm

创建

1. 用户态

assign_class_init
–>assigned_realize
–>get_real_device(根据指定的设备信息,从/sys/bus/pci/devices获取到所需的信息)
–>assigned_dev_register_regions(EPt建立好后,guest os访问gpa时就直接访问真实设备了不会有vm-exit发生) –>assign_device–>kvm_device_pci_assign–>kvm_vm_ioctl(s, KVM_ASSIGN_PCI_DEVICE, &dev_data)
–>assign_intx–>kvm_device_msix_deassign(以msix为例)–>kvm_deassign_irq_internal–>kvm_vm_ioctl(s, KVM_DEASSIGN_DEV_IRQ, &assigned_irq);

2.内核态

kvm_vm_ioctl_assigned_device
–>kvm_vm_ioctl_assign_device
–>kvm_iommu_map_guest–>iommu_domain_alloc(如果没有分配,为设备分配iommu_domain)
–>kvm_iommu_map_guest–>kvm_iommu_map_memslots–>kvm_iommu_map_pages(检查是否建立映射,用iommu_map建立映射) –>kvm_assign_device–>iommu_attach_device(将设备关联到iommu)


kvm_vm_ioctl_assigned_device
–>kvm_vm_ioctl_assign_irq


–>assign_host_irq
–>assigned_device_enable_host_msix(这里只分享msix)
–>注册了中断处理函数kvm_assigned_dev_msix和中断处理线程kvm_assigned_dev_thread_msix


–>assign_guest_irq
–>assigned_device_enable_guest_msix

中断管理

kvm_assigned_dev_raise_guest_irq
–>kvm_set_irq
–>kvm_irq_map_gsi

kvm_assigned_dev_msix
–>kvm_set_irq_inatomic
–>kvm_arch_set_irq_inatomic
–>kvm_irq_delivery_to_apic_fast

所以当中断发生的时候,发中断请求到apic

vfio

-device vfio-pci,host=01:10.0,id=net0

qemu

vfio_initfn
–>

  1. 验证主机上设备是否存在于/sys/bus/pci/devices/
  2. 获取到设备的groupid
  3. vfio_get_group根据groupid获取到group
    假设已经设置过此group下的设备,则直接返回缓存的group信息 否则,创建/dev/vfio/groupid并且通过VFIO_GROUP_GET_STATUS验证当前这个group是否可行
    vfio_connect_container–>VFIO_GROUP_SET_CONTAINER和VFIO_SET_IOMMU设置group和iommu的关联关系
    KVM_CREATE_DEVICE创建一个设备
    KVM_SET_DEVICE_ATTR设置设备的group属性为group->fd
  4. 检查设备是否已经设置过直通
  5. vfio_get_device
    通过VFIO_GROUP_GET_DEVICE_FD获取到设备的fd
    通过VFIO_DEVICE_GET_INFO获取到设备信息
  6. vfio_populate_device补齐设备相关信息
  7. 设置pci的配置空间(config)
  8. vfio_pci_size_rom设置rom相关
  9. vfio_map_bars设置内存相关
  10. vfio_add_capabilities–>vfio_add_std_cap–>msix_init假设这里是msix,初始化msix内容
  11. 假如PCI_INTERRUPT_PIN则注册vfio_update_irq作为回调函数
  12. vfio_enable_intx–>VFIO_DEVICE_SET_IRQS
  13. vfio_enable_intx–>vfio_enable_intx_kvm–>VFIO_DEVICE_SET_IRQS

内核

  1. VFIO_GROUP_SET_CONTAINER

vfio_group_set_container
–>attach_group(假设我们这里是vfio_iommu_type1)
–>vfio_iommu_type1_attach_group–>vfio_bus_type
–>vfio_iommu_type1_attach_group–>iommu_domain_alloc
–>vfio_iommu_type1_attach_group–>iommu_attach_group–>__iommu_attach_group–>__iommu_group_for_each_dev–>iommu_group_do_attach_device–>__iommu_attach_device–>intel_iommu_attach_device

  1. VFIO_SET_IOMMU
    vfio_ioctl_set_iommu
    –>__vfio_container_attach_groups
    –>attach_group

  2. VFIO_GROUP_GET_DEVICE_FD
    vfio_group_get_device_fd

4.VFIO_GROUP_GET_STATUS
vfio_group_viable
–>vfio_dev_viable

  1. KVM_CREATE_DEVICE
    kvm_ioctl_create_device

  2. KVM_SET_DEVICE_ATTR
    kvm_device_ioctl_attr
    –>kvm_vfio_set_attr
    –>kvm_vfio_set_group

  3. VFIO_DEVICE_GET_INFO

  4. VFIO_DEVICE_SET_IRQS vfio_pci_set_irqs_ioctl