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 主要解决了两个问题:

  1. 一方面为每个虚拟机创建了一个 DMA 保护域并实现了安全的隔离。
  2. 另一方面提供一种机制是将虚拟机的 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

  1. 确保 CPU 支持 Intel VT-d / AMD-Vi,并且已经在 Bios 中打开。

  2. 设置内核参数:

# Intel VT-d
intel_iommu=on

# AMD-Vi
amd_iommu=on

# Both,防止 Kernel 试图 Touching 无法 Passthrough 的设备。
iommu=pt
  1. 检查 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 的升级版,兼顾两者的优点,实现了:

  1. 在 User Space 配置 IOMMU interface,继而可以将 DMA 地址空间映射限制在用户态进程的虚拟空间中。从而解决了 UIO 不支持 DMA 的问题。
  2. Passthrough 的最小单元不再是某个单独的 PCI 设备,而是分布在同一个 IOMMU Group 的所有 PCI 设备;

可见,VFIO 最大的用途就是支撑 VNF 或 CNF 场景中 Passthrough 设备的用户态 I/O 实现。使用 VFIO 可以开发出安全的、非特权的、高性能的用户态的网卡驱动程序。

所以,VFIO 的本质与 UIO 一样,是一个用户态驱动框架。

一个 VFIO 设备表现为:

  • 用户态呈现:一个 /dev/vfio 设备文件。
  • 内核态呈现:一个 container 对象,一个 container 中可以包含多个 IOMMU Group。

它提供两种基本服务:

  1. 向用户态提供访问硬件设备的接口。
  2. 向用户态提供配置 IOMMU 的接口。

在这里插入图片描述

IOMMU Group

VFIO 是如何解决让多个 PCI 设备即 Passthrough 有可以互相访问的呢?换句话说:VFIO 如何让多个 PCI 设备一起 Passthrough?

为此 VFIO 引入了 IOMMU Group 的概念:

  1. 让若干个 VF(虚拟功能设备)同处于一个 IOMMU Group。
  2. 同时,把 IOMMU Group 作为 IOMMU 操作的最小单元。

即:一个 IOMMU Group 是将若干个 VFs 直通(Passthrough)给虚拟机的最小单位。

以上是关于Linux 操作系统原理 — 网络 I/O 虚拟化的主要内容,如果未能解决你的问题,请参考以下文章

Linux 操作系统原理 — I/O 处理流程

Linux I/O 原理和 Zero-copy 技术全面揭秘

Linux系统I/O模型和网络I/O模型

Java NIO预备知识:I/O底层原理与网络I/O模型

Linux系统I/O模型详解

第五十五课 linux系统调优 之cpu内存网络I/O