【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探 (2)

全虚拟化下Guest可以重用驱动、网络协议栈等,但是在软件全模拟的情况下,我们是否真的需要去访问寄存器吗(比如中断处理),真的需要模拟网卡的自协商机制以及EEPROM等功能吗?

是否真的需要模拟大量的硬件控制寄存器,而这些寄存器在软件看来毫无意义?

是否真的需要生产者/消费者模型的通知机制(寄存器访问、中断)?

3.1 virtio

网卡的工作过程是一个生产者消费者模型,但是在前文中可以看出,在全虚拟化状态下存在一些弊端,一个更好的生产者消费者模型应该遵循以下原则:

寄存器只被生产者使用去通知消费者ring-buffer有数据(消费者可以继续消费),而不再被用作存储状态信息;

中断被消费者用来通知生产者ring-buffer是非满状态(生产者可以继续生产);

生产者和消费者的状态信息应该存储在内存中,这样读取状态信息时不需要VM退出,减少overhead;

生产者和消费者跑在不同的线程中,可以并行运行,并且尽可能多的处理任务;

非必要情况下,相互之间的通知应该避免使用;

忙等待(比如轮询)不是一个可以接受的通用解决方案;

基于上述原则,我们来看看从特殊到一般的过程:

【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探

第一行是针对网卡的实现,第二行更进一步的抽象,第三行是通用的解决方案了,对I/O操作的虚拟化通用支持;

所以,在virtio的方案下,网卡的虚拟化看上去就是下边这个样子了:

【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探

Hypervisor和Guest都需要实现virtio,这也就意味着Guest的设备驱动知道自己本身运行在VM中;

virtio的目标是高性能的设备虚拟化,已经形成了规范来定义标准的消息传递API,用于驱动和Hypervisor之间的传递,不同的驱动和前端可以使用相同的API;

virtio驱动(比如图中的virtio-net driver)的工作是将OS-specific的消息转换成virtio格式的消息,而对端(virtio-net frontend)则是做相反的工作;

virtio的数据传递使用scatter-gather list(sg-list):

【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探

sg-list是概念上的(物理)地址和长度对的链表,通常作为数组来实现;

每个sg-list描述一个多块的buffer,消费者用它来作为输入或输出操作;

 
virtio的核心是virtqueue(VQ)的抽象:

VQ是队列,sg-list会被Guest的驱动放置到VQ中,以供Hypervisor来消费;

输出sg-list用于向Hypervisor来发送数据,而输入sg-list用于接收Hypervisor的数据;

驱动可以使用一个或多个virqueue;

【原创】Linux虚拟化KVM-Qemu分析(八)之virtio初探

当Guest的驱动产生一个sg-list时,调用add_buf(SG, Token)入列;

Hypervisor进行出列操作,并消费sg-list,并将sg-list push回去;

Guest通过get_buf()进行清理工作;

上图说的是数据流方向,那么事件的通知机制如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyffgy.html