本文原文链接:
https://developer.ibm.com/technologies/linux/articles/l-virtio/
Linux的 I / O 虚拟化 Virtio 框架
简而言之,virtio是半虚拟化管理程序中设备上的抽象层。virtio由Rusty Russell开发以支持他自己的虚拟化解决方案lguest。本文从准虚拟化和仿真设备的介绍开始,然后探讨的细节virtio。重点是virtio2.6.30内核发行版中的框架。
Linux是虚拟机管理程序平台。正如我在有关Linux作为虚拟机管理程序的文章中所展示的那样,Linux提供了各种具有不同属性和优点的虚拟机管理程序解决方案。
示例包括基于内核的虚拟机(KVM)lguest,和用户模式Linux。在Linux上拥有这些不同的虚拟机管理程序解决方案可以根据操作系统的独立需求来增加操作系统的负担。其中一项税项是设备虚拟化。它没有提供各种设备仿真机制(用于网络,块和其他驱动程序),而是virtio为这些设备仿真提供了一个通用的前端,以标准化接口并提高跨平台代码的重用性。
完全虚拟化与半虚拟化
让我们快速讨论两种不同类型的虚拟化方案:完全虚拟化和半虚拟化。
-
- 在完全虚拟化中,客户操作系统在裸机上的虚拟机管理程序之上运行。来宾不知道已对其进行了虚拟化,因此无需更改即可在此配置中工作。
-
- 在半虚拟化中,来宾操作系统不仅意识到它在虚拟机管理程序上运行,而且还包括使来宾到管理程序之间转换更加有效的代码(请参见图1)。
在完全虚拟化方案中,系统管理程序必须模拟设备硬件,该设备硬件在会话的最低级别上进行模拟(例如,模拟到网络驱动程序)。尽管在此抽象中仿真是干净的,但它也是效率最低且最复杂的。在超虚拟化方案中,来宾和管理程序可以协同工作以使此仿真高效。半虚拟化方法的缺点是,操作系统知道它已被虚拟化,因此需要进行修改才能工作。
图1.完全虚拟化和半虚拟化环境中的设备仿真
硬件随着虚拟化而不断变化。新的处理器结合了高级指令,以使客户机操作系统和虚拟机管理程序转换更加高效。而且,针对输入/输出(I / O)虚拟化的硬件也在不断变化(请参阅右侧的资源,了解外围控制器互连[PCI]直通以及单根和多根I / O虚拟化)。
但是在传统的完全虚拟化环境中,管理程序必须捕获这些请求,然后模拟真实硬件的行为。尽管这样做提供了最大的灵活性(即,运行未修改的操作系统),但确实会带来效率低下的问题(请参见图1的左侧)。图1的右侧显示了半虚拟化情况。在这里,来宾操作系统知道它正在虚拟机管理程序上运行,并包含充当前端的驱动程序。系统管理程序为特定的设备仿真实现后端驱动程序。这些前端和后端驱动程序virtio随处可见,为开发仿真设备访问提供了标准化的接口,以传播代码重用并提高效率。
Linux来宾的抽象
从上一节中,您可以看到这virtio是半虚拟化管理程序中一组常见仿真设备的抽象。这种设计允许管理程序导出一组通用的仿真设备,并通过通用的应用程序编程接口(API)使它们可用。图2说明了为什么这很重要。使用半虚拟化的虚拟机管理程序,来宾可实现一组通用的接口,而特定的设备仿真则位于一组后端驱动程序之后。后端驱动程序不需要通用,只要它们实现所需的前端行为即可。
图2.使用virtio的驱动程序抽象
请注意,实际上(尽管不是必需的),设备仿真是使用QEMU在用户空间中发生的,因此后端驱动程序会与虚拟机管理程序的用户空间进行通信,以方便通过QEMU进行I / O。QEMU是一种系统仿真器,除了提供客户机操作系统虚拟化平台外,还提供整个系统(PCI主机控制器,磁盘,网络,视频硬件,USB控制器和其他硬件元素)的仿真。
该virtioAPI依赖于简单的缓冲抽象来封装客体的指令和数据需求。让我们看一下virtioAPI及其组件的内部。
Virtio体系结构
除了前端驱动程序(在客户机操作系统中实现)和后端驱动程序(在虚拟机管理程序中实现)之外,还virtio定义了两层来支持客户机到管理程序之间的通信。在顶层(称为virtio)是虚拟队列接口,该接口在概念上将前端驱动程序附加到后端驱动程序。驱动程序可以根据需要使用零个或多个队列。例如,virtio网络驱动程序使用两个虚拟队列(一个用于接收,一个用于发送),而virtio块驱动程序仅使用一个。虚拟队列实际上是虚拟的,实际上是作为环来实现的,以遍历来宾到管理程序的过渡。但这可以以任何方式实现,只要来宾和系统管理程序都以相同的方式实现即可。
图3. virtio框架的高级架构
如图3所示,列出了五个前端驱动程序,分别用于块设备(例如磁盘),网络设备,PCI仿真,气球驱动程序(用于动态管理客户机内存使用)和控制台驱动程序。每个前端驱动程序在系统管理程序中都有一个对应的后端驱动程序。
概念层次
从来宾的角度来看,定义了一个对象层次结构,如图4所示。顶部是virtio_driver,它代表来宾中的前端驱动程序。与此驱动程序匹配的设备由virtio_device(来宾中设备的表示)封装。这是指virtio_config_ops结构(定义用于配置virtio设备的操作)的virtio_device是由称为virtqueue(其包括到一个参考virtio_device到其服务的)。最后,每个virtqueue对象都引用该virtqueue_ops对象,该对象定义了用于处理系统管理程序驱动程序的基础队列操作。尽管队列操作是virtio在API方面,我提供了有关发现的简短讨论,然后virtqueue_ops更详细地探讨了操作。
图4. virtio前端的对象层次结构
该过程始于创建,virtio_driver随后通过进行注册register_virtio_driver。该virtio_driver结构定义上层设备驱动程序,该驱动程序支持的设备ID列表,功能表(取决于设备类型)以及回调函数列表。当系统管理程序识别出存在与设备列表中的设备ID相匹配的新设备时,该probe函数将被调用(在virtio_driver对象中提供)以传递该virtio_device对象。该对象与设备的管理数据一起缓存(以驱动程序相关的方式)。根据驱动程序类型的不同,virtio_config_ops可以调用函数来获取或设置设备特定的选项(例如,获取磁盘的读/写状态)。virtio_blk 设备或设置块设备的块大小)。
请注意,virtio_device并未包含对的引用virtqueue(但virtqueue确实引用了virtio_device)。要标识virtqueue与此相关的virtio_device,请将该virtio_config_ops对象与find_vq函数一起使用。该对象返回与此virtio_device实例关联的虚拟队列。该find_vq函数还允许指定的回调函数virtqueue(请参见图4中的virtqueue结构),该回调函数用于将虚拟机管理程序的响应缓冲区通知给来宾。
s virtqueue是一个简单的结构,它标识一个可选的回调函数(在管理程序使用缓冲区时调用),对virtio_device的引用,对virtqueue操作的priv引用以及对要使用的基础实现的特殊引用。尽管callback可选,但可以动态启用或禁用回调。
但是,此层次结构的核心是virtqueue_ops,它定义了如何在来宾和系统管理程序之间移动命令和数据。让我们首先探讨从中添加或删除的对象virtqueue。
Virtio缓冲区
来宾(前端)驱动程序通过缓冲区与系统管理程序(后端)驱动程序通信。对于I / O,guest虚拟机提供一个或多个表示请求的缓冲区。例如,您可以提供三个缓冲区,第一个缓冲区代表读取请求,随后的两个缓冲区代表响应数据。在内部,此配置表示为一个分散聚集列表(列表中的每个条目代表一个地址和一个长度)。
核心API
链接来宾驱动程序和系统管理程序驱动程序通过进行virtio_device,最常见的是通过virtqueues进行。在virtqueue支持它自己的API包括五大功能。您使用第一个功能add_buf来向管理程序提供请求。该请求采用前面讨论的分散收集列表的形式。到add_buf,客户提供virtqueue给该请求要被排队时,分散-聚集列表(地址和长度的阵列),其充当了条目(目的地为基础管理程序)缓冲器的数量,和数量在条目中(系统管理程序将在该条目中存储数据并返回给来宾)。通过add_buf向虚拟机管理程序发出请求后,访客可以使用来将新请求通知虚拟机管理程序。kick功能。为了获得最佳性能,guest虚拟机应在virtqueue通过通知之前将尽可能多的缓冲区加载到上kick。
系统管理程序的响应通过该get_buf功能发生。来宾可以简单地通过调用此函数进行轮询,也可以通过提供的virtqueue callback函数等待通知。当来宾得知缓冲区可用时,调用会get_buf返回已完成的缓冲区。
virtqueueAPI中的最后两个函数是enable_cb和disable_cb。您可以使用这些函数来启用和禁用回调过程(通过在callback函数中初始化virtqueue的find_vq函数)。请注意,回调函数和管理程序位于单独的地址空间中,因此该调用通过间接管理程序调用(例如kvm_hypercall)进行。
缓冲区的格式,顺序和内容仅对前端和后端驱动程序有意义。内部传输(当前实现中的环)仅移动缓冲区,并且不知道其内部表示形式。
virtio驱动程序示例
您可以在Linux内核的./drivers子目录中找到各种前端驱动程序的源代码。
- virtio网络驱动程序可以在./drivers/net/virtio_net.c中找到;
- virtio块驱动程序可以在./drivers/block/virtio_blk.c找到;
- 子目录./drivers/virtio提供virtio接口(virtio设备,驱动程序virtqueue和环)的实现;
- virtio高性能计算(HPC)研究还通过共享内存传递来开发虚拟机(VM)通信。具体来说,这是通过使用virtioPCI驱动程序的虚拟PCI接口实现的。您可以在右侧的资源部分中了解有关此工作的更多信息。
构建自己的虚拟机(译者添加标题,利于理解virtio框架)
您现在可以在Linux内核中使用这种半虚拟化基础结构,来设计属于自己的虚拟机。您只需要一个充当虚拟机管理程序的内核,一个来宾内核和一个用于设备仿真的QEMU。
您可以使用KVM(主机内核中存在的模块)或Rusty Russell lguest(改良的Linux来宾内核)。这两种虚拟化解决方案均支持virtio(以及QEMU用于系统仿真和libvirt虚拟化管理)。
Rusty的工作成果是为半虚拟化驱动程序提供了更简单的代码库,并加快了虚拟设备的仿真速度。但是,更为重要的是,virtio与目前的商用解决方案相比,它提供了更好的性能(网络I / O的2-3倍)。这种性能提升需要付出一定的代价,但是如果Linux是您的虚拟机管理程序和来宾,则值得这样做。
拓展进阶
尽管您可能永远不会为开发前端驱动程序或后端驱动程序virtio,但是它实现了一个有趣的体系结构,值得更详细地了解。virtio在Xen以前的工作基础上,为半虚拟化I / O环境提供了提高效率的新机会。Linux继续证明自己是生产虚拟机管理程序和新虚拟化技术的研究平台。virtio这是Linux作为虚拟机管理程序的优势和开放性的又一个例子。
官方链接:
https://www.linux-kvm.org/page/Virtio
https://www.linux-kvm.org/page/KVM_Features