引言
设备虚拟化技术,仍然是云估算领域最重要的基础技术之一。我们在虚拟机上面看见的形形色色的设备虚拟机 linux系统,例如:网卡,c盘,鼠标,键盘等,都离不开这项技术的帮助。这篇文章,我们将从技术变迁的角度来谈一谈Linux现有的以及正式到来的设备虚拟化技术。
Trap-and-emulate
在最初期阶段,设备虚拟化往往和机器模拟器技术,例如:QEMU,绑定在一起。我们可以通过QEMU模拟真实设备的所有寄存器布局和操作流程,当QEMU虚拟机上面设备驱动须要访问该虚拟设备的寄存器时,这条访问指令会被trap到QEMU,由QEMU来进行处理。这样,虚拟机上面的设备驱动在操作该虚拟设备时如同在访问真实的硬件设备一样,设备驱动也不须要任何变更。
Virtio
通过上述这些trap-and-emulate的形式来模拟设备,即使不须要对真实设备驱动进行变更,并且设备访问过程中,频繁的深陷&陷出带来了严重的性能问题,因而,virtio这类半虚拟化技术应运而生,并于2008年合入Linux内核主线。
相较于trap-and-emulate这些方法,Virtio不再屈从于依赖已有的设备驱动,而是定义了一套全新的专用于虚拟设备的驱动框架。设备驱动清楚自己是在操作虚拟设备,因而,在真正的I/O路径上规避了大量可能造成深陷&陷出的mmio/pio操作,进而提升了性能。虚机上面的Virtio驱动和QEMU模拟的Virtio设备的数据交互,本质上是一套基于共享显存+环型队列的通讯机制。核心数据结构(splitvirtqueue)包括:两个ringbuffer(availring,usedring)和一个descriptortable。工作机制类似DMA,虚机内virtio驱动首先会将一个恳求在显存中须要传输的散列buffer的地址、长度组成一个个描述符写入到descriptortable中,之后将这种描述符对应的descriptortable上的index写入到availring中,并通过eventfd机制通知到宿主机上的virtiobackend。因为这种ringbuffer、descriptortable以及散列buffer都在共享显存中(虚机本质上是一个用户态进程,因而虚机显存是由用户态申请和分配,并可以share给其他进程,如:SPDK,DPDK等),因而red hat linux,VirtioBackend可以直接访问并获取到散列buffer的地址、长度,从而直接存取这种散列buffer。当处理完恳求以后,VirtioBackend将数据填充到相应的buffer,并将对应的descriptortableindex写入usedring中,并通过eventfd机制注入中断通知虚机内virtio驱动。
Vhost
Virtio技术提出以后,Virtio设备一般是在QEMU上面来进行模拟,数据收发都须要经过QEMU,再到虚机内部。但渐渐地,开发者们发觉,当模拟网卡时,在QEMU上面进行数据收发,最终都须要通过系统调用的方法,深陷内核来操作网卡硬件进行实际的数据收发。这么,QEMU到内核的此次上下文切换以及带来的额外拷贝开支,有没有办法优化呢?
Linux内核社区最终在2010年合入了vhost这个技术来进行优化,通过将virtio的数据面offload到一个内核线程来进行处理,这样virtio通讯机制从原先的QEMU用户态I/O线程和虚机驱动(QEMU用户态vcpu线程)通讯弄成了vhost内核I/O线程和虚机驱动(QEMU用户态vcpu线程)通讯。vhost内核I/O线程领到数据包然后,直接走内核合同栈和网卡驱动进行处理,因而优化掉了QEMU到内核态的额外开支。
VFIO
随着云估算规模的不断扩大,用户一方面不再满足于Virtio这类半虚拟化设备带来的性能体验,另一方面GPU这类很难进行virtio化的设备应用场景与日俱增。在这些背景下,VFIO这项技术被提出并在2012年合入Linux内核主线。VFIO全称是VirtualFunctionI/O,它实际是一个用户态设备驱动框架,相较于更早的uio这个用户态设备驱动框架,VFIO才能有效借助硬件IOMMU机制进行安全隔离,因而才能广泛地应用在云估算这类有多住户需求的场景中。
如上图所示,通过VFIO,QEMU才能直接将自己虚拟出的一个PCI设备和一个数学PCI设备的数据链路直接打通,当虚拟机上面的设备驱动访问虚拟PCI设备的bar空间时,通过EPT机制,此次mmio访问会被重定向到真实化学设备相应的bar空间位置,而不再须要trap到QEMU。这样,虚机驱动就相当于可以以接近零消耗的方法直接访问真实化学设备,性能可以达到最佳。同时,VFIO驱动借助IOMMU实现了设备DMA和中断的重映射,一方面起到隔离作用,即某个虚机难以操作VFIO直通设备向同一宿主机上的其他虚机发起DMA和中断,一方面也保证了设备进行DMA时通过给定的虚机化学地址就能直接访问到正确的化学显存。
Vhost-user
其实,VFIO才能给虚机带来接近化学机的I/O性能体验,但该技术仍存在一个缺陷,即不支持热迁移,带VFIO设备的虚机将无法像传统带virtio设备的虚机那样进行热迁移。这就促使开发者们,又开始找寻新的既能满足性能需求又具备运维灵活性的设备虚拟化技术。2014年QEMU社区合入的vhost-user技术就是其中之一,因为QEMU和vhost的线程模型对I/O性能的优化并不友好,但是由每位虚机单独分出线程来处理I/O这些方法从系统全局角度来看可能也并不是最优的,因而,vhost-user提出了一种新的方法,正式virtio设备的数据面offload到另一个专用进程来处理。这样,因为是专用进程,线程模型不再受传统QEMU和vhost线程模型阻碍,可以任意优化,同时,还可以以1:M的形式同时处理多个虚机的I/O恳求,但是相较于vhost这些内核线程形式,用户进程在运维方面愈发具备灵活性,vhost-user框架在提出之初,就遭到广泛关注,并引申出了SPDK和OVS-DPDK这类以polling+用户态驱动为核心的新的虚机I/O服务模型。
VFIO-mdev
VFIO技术在实际应用场景,不仅之前提到的不支持热迁移的问题外,还有一个限制就是一个设备只能透传给一个虚机,未能做到资源共享。SR-IOV技术从某种程度上就能解决这个问题,正式一个数学PCI设备从硬件层面进行资源界定,界定成多个VF,透传给多个虚机进行使用,而且有好多设备可能并不具备SR-IOV能力,为此,Linux内核社区在2016年合入了VFIO-mdev这个技术框架,希望提供一个标准的插口来帮助设备驱动实现软件层面的资源切分并就能借助VFIO技术透传给虚机。
该技术本质上是在内核实现了一个虚拟设备(Mediateddevice)总线驱动模型,并在VFIO内核框架上进行了扩充,降低了对mdev这类虚拟设备的支持(mdevbusdriver),从原先只支持从标准的硬件PCI设备和硬件platform设备获取透传信息,例如:PCIbar空间,弄成了既支持直接从硬件设备获取又可以从mdev设备驱动定义的虚拟设备插口来获取。这样,例如linux 分区,当须要将一个PCI设备的bar空间作为资源切分的话,通过实现合适的mdev设备驱动,就可以将bar空间以4KB(页面大小)为细度,分别透传给不同虚机使用。
vDPA
VFIO和virtio这两类技术仍然是最主流的设备虚拟化技术。VFIO就能直接将硬件资源透传给虚机使用,性能最佳,virtio性能稍逊,但胜在愈加灵活。那有没有可能将二者的优势结合上去呢?2020年被合入Linux内核主线的vDPA技术框架,就是为了实现这一目标。
vDPA的全称是VirtioDataPathAcceleration,它表示一类设备:这类设备的数据面处理是严格遵守Virtio合同规范的,即驱动和设备会根据第三节提及的Virtio通讯流程来进行通讯,但控制路径,例如:通讯流程上面提及的ringbuffer和descriptortable的显存地址,驱动怎样告知设备,设备支持的特点,驱动怎样感知,那些都是厂商自定义的,不一定会遵守Virtio合同。这样做的用处是虚拟机 linux系统,可以增加厂商在实现这类设备时的复杂度。
Linux内核为了将这类设备应用上去,就提出了vDPA这样一个技术框架。这个技术框架本质上和VFIO-mdev类似,也实现了一个虚拟设备(vDPAdevice)总线驱动模型,和VFIO-mdev不同的是,通过vDPA框架虚拟下来的设备,既可以给虚机使用,又可以直接从宿主机(例如:容器)进行访问。这一切都归功于,vDPA设备的数据路径是依循Virtio合同规范的,因而,可以直接被宿主机上的virtio驱动直接访问。同时,该技术框架对vhost内核子系统进行了扩充,赋于了类似VFIO技术框架的功能,容许将vDPA设备拿来进行数据通讯的硬件资源(ringbuffer,descriptortable,doorbell寄存器等)透传给虚机使用,这样,虚拟机的virtio驱动进行数据通讯时,也是直接访问硬件资源,而不再须要通过vhost、vhost-user等方法进行处理了。更重要的一点是,因为虚机驱动是先前的virtio驱动,因而,当须要支持热迁移时,QEMU可以灵活切换会软件模拟的方法,来保证热迁移的顺利进行。这样,vDPA这个设备虚拟化技术框架既保证了最佳性能又保留了virtio设备的灵活性,并且还统一了虚机和容器的I/O技术栈。
VDUSE
通过上述vDPA技术框架,我们基本解决了常年以来设备虚拟化技术在虚机场景下曝露的一些问题,而更重要的是,它将virtio技术也带到了容器领域。但这个技术框架还存在一个问题,就是须要硬件设备的支持。回想之前提到的virtio、vhost、vhost-user,本质上都是软件定义的虚拟设备。那vDPA这个技术框架有没有可能也就能使用软件定义的设备呢?VDUSE这项技术就是拿来实现这个目标的,通过VDUSE,我们可以在一个用户进程实现一个软件定义的vDPA设备,并可以通过上述vDPA框架接入virtio或则vhost子系统,供容器或则虚机使用。
该项技术是由我们自主研制并在今年10月向Linux内核社区即将开源的。现阶段我们的方案早已被合入Linux内核主线,将在Linux5.15版本与你们碰面。同时,我们也会在9月15日举行的KVMForum这个虚拟化领域的高档技术峰会大会上进行线上分享。
结束语
从服务虚拟机到支持容器,从纯软件模拟到硬件直通再到软硬件结合,Linux设备虚拟化技术这几六年里仍然在朝着极至性能、应用灵活等方向不断演化。随着云原生的浪潮,各大硬件厂商的入局,全新的软硬件结合形式不断涌现,我们相信后续也会有更多精彩技术在等待着我们。
参考链接
~rusty/virtio-spec/virtio-paper.pdf