概而言之,virtio
是半虚拟化 hypervisor 中位于设备之上的抽象层。virtio
由 Rusty Russell 开发,他当时的目的是支持自己的虚拟化解决方案 lguest
。本文在开篇时介绍半虚拟化和模拟设备,然后探索 virtio
的细节。本文的重点是来自 2.6.30 内核发行版的 virtio
框架。
Linux 是 hypervisor 展台。如我的 剖析 Linux hypervisor
所述,Linux 提供各种 hypervisor 解决方案,这些解决方案都有自己的特点和优点。这些解决方案包括 Kernel-based Virtual Machine (KVM)、lguest
和 User-mode Linux 等。在 Linux 上配备这些不同的 hypervisor 解决方案会给操作系统带来负担,负担的大小取决于各个解决方案的需求。其中的一项开销为设备的虚拟化。virtio
并没有提供多种设备模拟机制(针对网络、块和其他驱动程序),而是为这些设备模拟提供一个通用的前端,从而标准化接口和增加代码的跨平台重用。
完全虚拟化和半虚拟化
让我们快速讨论一下两种类型完全不同的虚拟化模式:完全虚拟化和半虚拟化。在完全虚拟化
中,来宾操作系统运行在位于物理机器上的 hypervisor 之上。来宾操作系统并不知道它已被虚拟化,并且不需要任何更改就可以在该配置下工作。相反,在半虚拟化
中,来宾操作系统不仅知道它运行在 hypervisor 之上,还包含让来宾操作系统更高效地过渡到 hypervisor 的代码(见 图 1
)。
在完全虚拟化模式中,hypervisor 必须模拟设备硬件,它是在会话的最低级别进行模拟的(例如,网络驱动程序)。尽管在该抽象中模拟很干净,但它同时也是最低效、最复杂的。在半虚拟化模式中,来宾操作系统和 hypervisor 能够共同合作,让模拟更加高效。半虚拟化方法的缺点是操作系统知道它被虚拟化,并且需要修改才能工作。
图 1. 在完全虚拟化和半虚拟化环境下的设备模拟
硬件随着虚拟化技术而不断改变。新的处理器通过纳入高级指令来让来宾操作系统到 hypervisor 的过渡更加高效。此外,硬件也随着输入/输出(I/O)虚拟化而不断改变(参见 参考资料
了解 Peripheral Controller Interconnect [PCI] passthrough 和 single- and
multi-root I/O 虚拟化)。
但是在传统的完全虚拟化环境中,hypervisor 必须捕捉这些请求,然后模拟物理硬件的行为。尽管这样做提供很大的灵活性(即运行未更改的操作系统),但它的效率比较低(参见 图 1
左边)。图 1 的右边是半虚拟化示例。在这里,来宾操作系统知道它运行在 hypervisor 之上,并包含了充当前端的驱动程序。Hypervisor 为特定的设备模拟实现后端驱动程序。通过在这些前端和后端驱动程序中的 virtio
,为开发模拟设备提供标准化接口,从而增加代码的跨平台重用率并提高效率。
针对 Linux 的抽象
从前面的小节可以看到,virtio
是对半虚拟化 hypervisor 中的一组通用模拟设备的抽象。该设置还允许 hypervisor 导出一组通用的模拟设备,并通过一个通用的应用编程接口(API)让它们变得可用。图 2
展示了为什么这很重要。有了半虚拟化 hypervisor 之后,来宾操作系统能够实现一组通用的接口,在一组后端驱动程序之后采用特定的设备模拟。后端驱动程序不需要是通用的,因为它们只实现前端所需的行为。
图 2. virtio 的驱动程序抽象
注意,在现实中(尽管不需要),设备模拟发生在使用 QEMU 的空间,因此后端驱动程序与 hypervisor 的用户空间交互,以通过 QEMU 为 I/O 提供便利。QEMU 是一个系统模拟器,它不仅提供来宾操作系统虚拟化平台,还提供整个系统(PCI 主机控制器、磁盘、网络、视频硬件、USB 控制器和其他硬件元素)的模拟。
virtio
API 依赖一个简单的缓冲抽象来封装来宾操作系统需要的命令和数据。让我们查看 virtio
API 的内部及其组件。
Virtio 架构
除了前端驱动程序(在来宾操作系统中实现)和后端驱动程序(在 hypervisor 中实现)之外,virtio
还定义了两个层来支持来宾操作系统到 hypervisor 的通信。在顶级(称为 virtio
)的是虚拟队列接口,它在概念上将前端驱动程序附加到后端驱动程序。驱动程序可以使用 0 个或多个队列,具体数量取决于需求。例如,virtio
网络驱动程序使用两个虚拟队列(一个用于接收,另一个用于发送),而 virtio
块驱动程序仅使用一个虚拟队列。虚拟队列实际上被实现为跨越来宾操作系统和 hypervisor 的衔接点。但这可以通过任意方式实现,前提是来宾操作系统和 hypervisor 以相同的方式实现它。
图 3. vital 框架的高级架构
如 图 3
所示,分别为块设备(比如磁盘)、网络设备、PCI 模拟和 balloon 驱动程序列出了 5 个前端驱动程序。每个前端驱动程序在 hypervisor 中有一个对应的后端驱动程序。
概念层次结构
从来宾操作系统的角度来看,对象层次结构
的定义如 图 4
所示。在顶级的是 virtio_driver
,它在来宾操作系统中表示前端驱动程序。与该驱动程序匹配的设备由 virtio_device
(设备在来宾操作系统中的表示)封装。这引用 virtio_config_ops
结构(它定义配置 virtio
设备的操作)。virtio_device
由 virtqueue
引用(它包含一个到它服务的 virtio_device
的引用)。最后,每个 virtqueue
对象引用 virtqueue_ops
对象,后者定义处理 hypervisor 的驱动程序的底层队列操作。尽管队列操作是 virtio
API 的核心,我还是先简单讨论一下新的发现,然后再详细探讨 virtqueue_ops
操作。
图 4. virtio 前端的对象层次结构
该流程以创建 virtio_driver
并通过 register_virtio_driver
进行注册开始。virtio_driver
结构定义上层设备驱动程序、驱动程序支持的设备 ID 的列表、一个特性表单(取决于设备类型)和一个回调函数列表。当 hypervisor 识别到与设备列表中的设备 ID 相匹配的新设备时,将调用 probe
函数(由 virtio_driver
对象提供)来传入 virtio_device
对象。将这个对象和设备的管理数据缓存起来(以独立于驱动程序的方式缓存)。可能要调用 virtio_config_ops
函数来获取或设置特定于设备的选项,例如,为 virtio_blk
设备获取磁盘的 Read/Write 状态或设置块设备的块大小,具体情况取决于启动器的类型。
注意,virtio_device
不包含到 virtqueue
的引用(但 virtqueue
确实引用了 virtio_device
)。要识别与该 virtio_device
相关联的 virtqueue
,您需要结合使用 virtio_config_ops
对象和 find_vq
函数。该对象返回与这个 virtio_device
实例相关联的虚拟队列。find_vq
函数还允许为 virtqueue
指定一个回调函数(查看 图 4
中的 virtqueue
结构)。
virtqueue
是一个简单的结构,它识别一个可选的回调函数(在 hypervisor 使用缓冲池时调用)、一个到 virtio_device
的引用、一个到 virtqueue
操作的引用,以及一个引用要使用的底层实现的特殊 priv
引用。虽然 callback
是可选的,但是它能够动态地启用或禁用回调。
该层次结构的核心是 virtqueue_ops
,它定义在来宾操作系统和 hypervisor 之间移动命令和数据的方式。让我们首先探索添加到或从 virtqueue
移除的对象。
Virtio 缓冲池
来宾操作系统(前端)驱动程序通过缓冲池与 hypervisor 交互。对于 I/O,来宾操作系统提供一个或多个表示请求的缓冲池。例如,您可以提供 3 个缓冲池,第一个表示 Read 请求,后面两个表示响应数据。该配置在内部被表示为一个散集列表(scatter-gather),列表中的每个条目表示一个地址和一个长度。
核心 API
通过 virtio_device
和 virtqueue
(更常见)将来宾操作系统驱动程序与 hypervisor 的驱动程序链接起来。virtqueue
支持它自己的由 5 个函数组成的 API。您可以使用第一个函数 add_buf
来向 hypervisor 提供请求。如前面所述,该请求以散集列表的形式存在。对于 add_buf
,来宾操作系统提供用于将请求添加到队列的 virtqueue
、散集列表(地址和长度数组)、用作输出条目(目标是底层 hypervisor)的缓冲池数量,以及用作输入条目(hypervisor 将为它们储存数据并返回到来宾操作系统)的缓冲池数量。当通过 add_buf
向 hypervisor 发出请求时,来宾操作系统能够通过 kick
函数通知 hypervisor 新的请求。为了获得最佳的性能,来宾操作系统应该在通过 kick
发出通知之前将尽可能多的缓冲池装载到 virtqueue
。
通过 get_buf
函数触发来自 hypervisor 的响应。来宾操作系统仅需调用该函数或通过提供的 virtqueue callback
函数等待通知就可以实现轮询。当来宾操作系统知道缓冲区可用时,调用 get_buf
返回完成的缓冲区。
virtqueue
API 的最后两个函数是 enable_cb
和 disable_cb
。您可以使用这两个函数来启用或禁用回调进程(通过在 virtqueue
中由 virtqueue
初始化的 callback
函数)。注意,该回调函数和 hypervisor 位于独立的地址空间中,因此调用通过一个间接的 hypervisor 来触发(比如 kvm_hypercall
)。
缓冲区的格式、顺序和内容仅对前端和后端驱动程序有意义。内部传输(当前实现中的连接点)仅移动缓冲区,并且不知道它们的内部表示。
示例 virtio 驱动程序
您可以在 Linux 内核的 ./drivers 子目录内找到各种前端驱动程序的源代码。可以在 ./drivers/net/virtio_net.c 中找到 virtio
网络驱动程序,在 ./drivers/block/virtio_blk.c 中找到 virtio
块驱动程序。子目录 ./drivers/virtio 提供 virtio
接口的实现(virtio
设备、驱动程序、virtqueue
和连接点)。virtio
还应用在 High-Performance
Computing (HPC) 研究中,以开发出通过共享内存传递的 inter-virtual machine (VM) 通信。尤其是,这是通过使用
virtio
PCI 驱动程序的虚拟化 PCI 接口实现的。您可以在 参考资料
部分更多地了解这个知识点。
现在,您可以在 Linux 内核中实践这个半虚拟化基础架构。您所需的包括一个充当 hypervisor 的内核、一个来宾操作性内核和用于设备模拟的 QEMU。您可以使用 KVM(位于主机内核中的一个模块)或 Rusty Russell 的 lguest
(修改版的 Linux 来宾操作系统内核)。这两个虚拟化解决方案都支持 virtio
(以及用于系统模拟的 QEMU 和用于虚拟化管理的 libvirt
)。
Rusty 的 lguest
是针对半虚拟化驱动程序和更快速地模拟虚拟设备的更简洁代码库。但更重要的是,实践证明 virtio
比现有的商业解决方案提供更出色的性能(网络 I/O 能够提升 2-3 倍)。性能的提升是需要付出代价的,但是如果您使用 Linux 作为 hypervisor 和来宾操作系统,那么这样做是值得的。
结束语
也许您可能从来没有为 virtio
开发过前端或后端驱动程序,它实现了一个有趣的架构,值得您仔细去探索。virtio
为提高半虚拟化 I/O 环境中的效率带来了新的机会,同时能够利用 Xen 以前的成果。Linux 不断地证明它是一个产品 hypervisor,并且是新虚拟化技术研究平台。virtio
这个例子展示了将 Linux 用作 hypervisor 的强大之处和开放性。
本文转载于developerWorks,原文在这里
分享到:
相关推荐
- **Virtio**:一种用于提高虚拟化环境中I/O效率的框架。 - **vring**:一种高效的环形缓冲区传输机制。 - **virtiopci**:将virtio设备呈现为PCI设备的一种实现方式。 - **Virtualization**:通过软件模拟硬件功能...
总而言之,Virtio通过提供一个统一的I/O虚拟化框架,简化了不同虚拟化系统间设备驱动的兼容性问题,提高了性能,同时也便于设备供应商和系统管理员的使用。随着虚拟化技术在云计算和数据中心管理中变得越来越重要,...
Virtio是一个重要的虚拟化技术框架,主要用于提高虚拟机(VM)与宿主机之间的I/O性能。这个名为“Virtio.tar.gz”的压缩包包含了官方的Virtio介绍文档,帮助我们深入理解这一关键技术。 首先,Virtio的核心概念是...
Virtio是一种在虚拟化环境中用于简化和标准化虚拟I/O设备的框架,主要用于Linux内核中。它的主要目的是解决虚拟化技术中由于每个虚拟化系统都拥有自己特定的驱动程序(如块、网络、控制台等驱动)所带来的各种问题,...
virtio是一种高性能的I/O半虚拟化框架,旨在减少虚拟化带来的性能损失。它通过提供一个通用的接口来连接客户操作系统和宿主系统的设备驱动程序,从而提高了I/O操作的效率。在KVM环境中,virtio主要用于实现客户机与...
Linux虚拟化中的virtio驱动程序可以使用标准Linux内核PCI和驱动程序框架。 #### 与非信任方的通信 在虚拟化环境中,与非信任方(例如其他虚拟机)通信时,Virtio PCI设备的实现需要完全访问guest内存。因此,非...
Virtio-blk是Linux虚拟化中一个重要的前端驱动,用于在虚拟机和宿主机之间高效传输块设备请求。本文将详细介绍virtio-blk在Linux虚拟机中处理读取请求(read request)的流程。 首先,VIRTIO是一种虚拟传输协议,它...
14. DPDK 的 I/O 接口:DPDK 支持各种 I/O 的 SR-IOV 接口和 virtio 接口,可以满足高性能虚拟主机网络的要求。 15. rte_eal_init 的工作:rte_eal_init 是 DPDK 的一个核心函数,完成了包括配置初始化、内存初始化...
虚拟化主要分为两类:I型虚拟化和II型虚拟化。I型虚拟化,也称为裸金属虚拟化,Hypervisor直接运行在硬件上,不依赖于任何操作系统。II型虚拟化,也称为宿主型虚拟化,Hypervisor运行在宿主操作系统之上。这两种类型...
QEMU负责处理虚拟机的I/O操作,而KVM则处理CPU虚拟化。 在没有VHE特性的环境中,虚拟化架构通常需要更复杂的模拟层来处理硬件资源。虚拟机监控程序需要模拟更多的硬件细节,这会导致更高的性能开销。相反,当VHE...
标题中的"virtio_caif.rar_SOC"暗示了我们讨论的主题是关于虚拟化设备接口Virtio和CAIF(Cellular Application Interface Framework)在系统级芯片(SoC)环境中的应用。"SOC"通常指的是System on Chip,即集成了...
在文件内容中还提及了Virtio,这是一种虚拟I/O设备的标准,广泛用于虚拟化环境。Virtio提供了一套标准的前端驱动程序接口和后端设备实现,允许虚拟化环境中的设备以接近物理设备性能的方式工作。 文件中出现的代码...
KVM本身是一个嵌入在Linux内核中的Type 1 Hypervisor,提供完全虚拟化解决方案,使得虚拟机的vCPU指令可以直接在物理CPU上执行。 【Fuzzer的制作】 为了提高QEMU的安全性,开发者和安全研究人员采用了各种方法进行...
- **virtio**:虚拟化设备的属性,用于描述虚拟化环境中的设备。 Device TreeSpecification详细介绍了这些概念,并提供了更多高级特性和用例,如中断控制器描述、时钟框架、电源管理等。通过理解和应用这份规范,...
2.6. 使用Vhost-user进行虚拟化I / O. 16 2.6.1 介绍 16 2.6.2 QEMU 17 2.6.3 设备初始化 18 2.6.4 I / O路径 19 2.6.5 SPDK优化 20 2.7. SPDK目录结构概述 20 2.8. SPDK移植指南 22 第三章 用户指南 22 3.1. 系统...
9. **虚拟化技术**:在虚拟字符设备的场景中,可能涉及Linux的VirtIO框架,它提供了一种高效的方法在虚拟机和宿主机之间通信,使得虚拟设备能在无须模拟硬件的情况下工作。 10. **文件系统交互**:驱动程序需要与...
所有艰苦的工作和实际的虚拟化工作都是由Virtualization.framework执行的-这个包装器只是简单地设置配置对象,以描述VM。 它旨在作为此框架的最简单调用,同时允许配置: 内存量 VCPU数量 附加的光盘映像,CDROM...
虚拟化框架提供了高级API,用于在Apple芯片和基于Intel的Mac计算机上创建和管理虚拟机。 使用此框架可以在您定义的自定义环境中引导和运行基于Linux的操作系统。 该框架支持Virtio规范,该规范为许多设备类型定义了...