Linux 操作系统原理 — 网络 I/O 虚拟化
Posted 范桂飓
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 操作系统原理 — 网络 I/O 虚拟化相关的知识,希望对你有一定的参考价值。
目录
文章目录
IOMMU — CPU 硬件支撑的 I/O 虚拟化方案
需求背景
多个虚拟机共享服务器中的物理网卡,该场景中需要一种机制既能保证 I/O 的效率,又要保证多个虚拟机对用物理网卡共享使用。I/O 虚拟化的出现就是为了解决这类问题。
DMA Remapping Feature
从 CPU 的角度看,为了解决虚拟机访问物理网卡等 I/O 设备的性能问题,就是要避免 VMM 对 CPU 指令的捕获/翻译、上下文切换、内存拷贝等损耗,于是提出了 DMA Remapping Feature(DMA(直接存储器存取)的重映射功能),即:虚拟机可以通过 DMA Remapping Feature 直接访问到宿主机的物理网卡设备的内存空间,且进行安全访问,故称这段地址空间为:虚拟机对网卡访问的 DMA 保护域。
DMA Remapping Feature 主要解决了两个问题:
- 一方面为每个虚拟机创建了一个 DMA 保护域并实现了安全的隔离。
- 另一方面提供一种机制是将虚拟机的 Guest Physical Address 翻译为物理机的 Host Physical Address。从而虚拟机访问自己的地址就是直接访问宿主机分配给网卡的地址。
IOMMU 硬件单元
DMA Remapping Feature 的工作是通过 CPU 硬件平台的 IOMMU(I/O MMU,Input/Output Memory Management Unit,I/O 内存管理硬件单元)来完成的。IOMMU 的出现,实现了地址空间上的隔离,使设备只能访问规定的内存区域。
Intel VT-d 和 AMD-Vi 都是 IOMMU 的一种硬件实现:
- Intel VT-d(Intel Virtualization Technology for Directed I/O,Intel 的直接 I/O 虚拟化):用于提高虚拟化的安全性、可靠性和 I/O 性能。
- AMD-Vi(AMD’s I/O Virtualization Technology,AMD 的 I/O 虚拟化技术):作用同上。
PCI Passthrough
传统的虚拟化方案是虚拟机通过 Hypervisor 来共享的访问一个物理网卡,当 Hypervisor 需要处理多台虚拟机对同一个设备的并发访问和隔离时,Hypervisor 就成为了一个性能瓶颈。
那么,既然虚拟机可以通过 IOMMU 来访问网卡的 DMA,那么更彻底的做法就是把整块网卡 Passthrough(直通)给虚拟机使用,即:虚拟机绕过 Hypervisor 直接操作物理网卡。这种做法称作 PCI Passthrough。VMware,Xen 和 KVM 都支持这种技术。
主流的网卡设备商随即推出 SR-IOV(Single Root IO Virtualization)和 MR-IOV(Multi-Root IO Virtualization)技术,将一个 PF 硬件虚拟化为 VF,继而一张网卡可以化作多个 PCI/PCIe 设备,并 Passthrough 使用。
值得注意的是,在一些场景中,多个 PCI 设备之间是存在协作关系的,它们互相协作组成一个功能的实体,彼此之间也需要相互访问。而 IOMMU 对该场景中的这些设备是不适用的。
开启 IOMMU
Kernel 开启 IOMMU 之后就可以使用 Intel VT-d / AMD-Vi,以及 PCI Passthrough 功能了,同时还作用于应对故障及恶意行为的内存保护。
启用 IOMMU:
-
确保 CPU 支持 Intel VT-d / AMD-Vi,并且已经在 Bios 中打开。
-
设置内核参数:
# Intel VT-d
intel_iommu=on
# AMD-Vi
amd_iommu=on
# Both,防止 Kernel 试图 Touching 无法 Passthrough 的设备。
iommu=pt
- 检查 dmesg 以确认 IOMMU 已经被正确启用:
$ dmesg | grep -e DMAR -e IOMMU
[ 0.000000] DMAR: IOMMU enabled
UIO Framework — 用户态网络协议栈方案
UIO Framework Kernel Module(User Space I/O,用户态 I/O 框架内核模块),是 Kernel 提供的用户态 I/O 驱动程序框架。基于 UIO Framework 可以编写出让数据报文绕过 Kernel Network Stack,直接进入 User Space 进行处理的内核模块(e.g. DPDK IGB_UIO)。
但是,UIO 也有着不足之处,例如:不支持 DMA(不受 IOMMU 的保护)、中断支持有限、需要 Root 权限运行等,所以通过 DMA 传输大流量数据的 I/O 设备,如:被 Passthrougth 的网卡、显卡等设备,是无法使用 UIO Framework 的。
UIO 的实现机制是:对用户态暴露一个文件接口,当注册一个 UIO 设备时,就会出现一个系统文件 /dev/uioX,对该文件的读写就是对网卡设备的内存的读写。除此之外,对网卡设备的控制还可以通过 /sys/class/uio 下的各个文件的读写来完成。
如下图:
- mmap() 接口:用于映射设备的寄存器空间。
- read() 接口:用于等待一个设备中断。
- write() 接口:用于控制中断关闭/打开。
VFIO — VNF/CNF 的用户态网络协议栈方案
上述:
- UIO 的作用是支持用户态网络协议栈,问题是不支持 DMA。
- IOMMU 的作用是支持 DMA Remapping 功能,问题是无法让多个 PCI 设备互相访问。
VFIO(Virtual Function I/O)就是 UIO 和 IOMMU 的升级版,兼顾两者的优点,实现了:
- 在 User Space 配置 IOMMU interface,继而可以将 DMA 地址空间映射限制在用户态进程的虚拟空间中。从而解决了 UIO 不支持 DMA 的问题。
- Passthrough 的最小单元不再是某个单独的 PCI 设备,而是分布在同一个 IOMMU Group 的所有 PCI 设备;
可见,VFIO 最大的用途就是支撑 VNF 或 CNF 场景中 Passthrough 设备的用户态 I/O 实现。使用 VFIO 可以开发出安全的、非特权的、高性能的用户态的网卡驱动程序。
所以,VFIO 的本质与 UIO 一样,是一个用户态驱动框架。
一个 VFIO 设备表现为:
- 用户态呈现:一个 /dev/vfio 设备文件。
- 内核态呈现:一个 container 对象,一个 container 中可以包含多个 IOMMU Group。
它提供两种基本服务:
- 向用户态提供访问硬件设备的接口。
- 向用户态提供配置 IOMMU 的接口。
IOMMU Group
VFIO 是如何解决让多个 PCI 设备即 Passthrough 有可以互相访问的呢?换句话说:VFIO 如何让多个 PCI 设备一起 Passthrough?
为此 VFIO 引入了 IOMMU Group 的概念:
- 让若干个 VF(虚拟功能设备)同处于一个 IOMMU Group。
- 同时,把 IOMMU Group 作为 IOMMU 操作的最小单元。
即:一个 IOMMU Group 是将若干个 VFs 直通(Passthrough)给虚拟机的最小单位。
以上是关于Linux 操作系统原理 — 网络 I/O 虚拟化的主要内容,如果未能解决你的问题,请参考以下文章