附加处理器 (AP) 设施¶
简介¶
附加处理器 (AP) 设施是一个 IBM Z 加密设施,由三个 AP 指令和 1 到 256 个 PCIe 加密适配器卡组成。AP 设备为分配给在 IBM Z 系统 LPAR 中运行的 Linux 系统中的所有 CPU 提供加密功能。
AP 适配器卡通过 AP 总线公开。vfio-ap 的动机是使用 VFIO 调解设备框架使 AP 卡可用于 KVM 虚拟机。此实现很大程度上依赖于 s390 虚拟化设施,该设施完成了提供对 AP 设备的直接访问的大部分繁重工作。
AP 架构概述¶
为了方便理解设计,让我们从一些定义开始
AP 适配器
AP 适配器是一种 IBM Z 适配器卡,可以执行加密功能。可以有 0 到 256 个适配器分配给一个 LPAR。分配给运行 Linux 主机的 LPAR 的适配器将可用于 Linux 主机。每个适配器都由一个 0 到 255 的数字标识;但是,最大适配器编号由机器型号和/或适配器类型确定。安装后,任何 CPU 执行的 AP 指令都将访问 AP 适配器。
AP 适配器卡通过系统的激活配置文件分配给给定的 LPAR,可以通过 HMC 编辑该文件。当 Linux 主机系统在 LPAR 中 IPL 时,AP 总线会检测分配给 LPAR 的 AP 适配器卡,并为每个分配的适配器创建一个 sysfs 设备。例如,如果将 AP 适配器 4 和 10 (0x0a) 分配给 LPAR,则 AP 总线将创建以下 sysfs 设备条目
/sys/devices/ap/card04 /sys/devices/ap/card0a
在 AP 总线设备子目录中也会创建指向这些设备的符号链接
/sys/bus/ap/devices/[card04] /sys/bus/ap/devices/[card04]
AP 域
一个适配器被划分为多个域。一个适配器最多可以容纳 256 个域,具体取决于适配器类型和硬件配置。域由一个 0 到 255 的数字标识;但是,最大域编号由机器型号和/或适配器类型确定。可以将域视为一组用于处理 AP 命令的硬件寄存器和内存。可以使用用于清除密钥加密的安全私钥配置域。域根据其访问方式分为两种方式之一
使用域是 AP 指令定向以处理 AP 命令的域。
控制域是通过发送到使用域的 AP 命令更改的域;例如,设置控制域的安全私钥。
AP 使用域和控制域通过系统的激活配置文件分配给给定的 LPAR,可以通过 HMC 编辑该文件。当 Linux 主机系统在 LPAR 中 IPL 时,AP 总线模块会检测分配给 LPAR 的 AP 使用域和控制域。每个使用域的域编号和每个 AP 适配器的适配器编号组合在一起,以创建 AP 队列设备(请参见下面的 AP 队列部分)。每个控制域的域编号将以位掩码形式表示,并存储在 sysfs 文件 /sys/bus/ap/ap_control_domain_mask 中。掩码中的位,从最高有效位到最低有效位,对应于域 0-255。
AP 队列
AP 队列是将 AP 命令发送到特定适配器内的使用域的方式。AP 队列由包含 AP 适配器 ID (APID) 和 AP 队列索引 (APQI) 的元组标识。APQI 对应于适配器内的给定使用域编号。此元组形成唯一标识 AP 队列的 AP 队列号 (APQN)。AP 指令包含一个字段,其中包含 APQN,以标识要将 AP 命令发送到哪个 AP 队列进行处理。
AP 总线将为每个 APQN 创建一个 sysfs 设备,该 APQN 可以从加载 AP 总线模块时检测到的 AP 适配器和使用域编号的叉积中派生出来。例如,如果适配器 4 和 10 (0x0a) 以及使用域 6 和 71 (0x47) 被分配给 LPAR,则 AP 总线将创建以下 sysfs 条目
/sys/devices/ap/card04/04.0006 /sys/devices/ap/card04/04.0047 /sys/devices/ap/card0a/0a.0006 /sys/devices/ap/card0a/0a.0047
将在 AP 总线设备子目录中创建指向这些设备的以下符号链接
/sys/bus/ap/devices/[04.0006] /sys/bus/ap/devices/[04.0047] /sys/bus/ap/devices/[0a.0006] /sys/bus/ap/devices/[0a.0047]
AP 指令
有三个 AP 指令
NQAP:将 AP 命令请求消息排入队列
DQAP:从队列中取消 AP 命令回复消息的排队
PQAP:管理队列
AP 指令标识要处理 AP 命令的目标域;这必须是使用域之一。AP 命令可以修改不是使用域之一的域,但是修改后的域必须是控制域之一。
AP 和 SIE¶
现在让我们看一下硬件如何解释在虚拟机上执行的 AP 指令。
一个名为加密控制块 (CRYCB) 的卫星控制块附加到我们的主要硬件虚拟化控制块。CRYCB 包含一个 AP 控制块 (APCB),该控制块具有三个字段来标识分配给 KVM 虚拟机的适配器、使用域和控制域
AP 掩码 (APM) 字段是一个位掩码,用于标识分配给 KVM 虚拟机的 AP 适配器。掩码中的每一位,从左到右,对应于 0-255 的 APID。如果设置了某一位,则对应的适配器可供 KVM 虚拟机使用。
AP 队列掩码 (AQM) 字段是一个位掩码,用于标识分配给 KVM 虚拟机的 AP 使用域。掩码中的每一位,从左到右,对应于 0-255 的 AP 队列索引 (APQI)。如果设置了某一位,则对应的队列可供 KVM 虚拟机使用。
AP 域掩码字段是一个位掩码,用于标识分配给 KVM 虚拟机的 AP 控制域。ADM 位掩码控制哪些域可以被从虚拟机发送到使用域的 AP 命令请求消息更改。掩码中的每一位,从左到右,对应于 0-255 的域。如果设置了某一位,则可以通过发送到使用域的 AP 命令请求消息来修改对应的域。
如果您还记得 AP 队列的描述,AP 指令包含一个 APQN,用于标识要将 AP 命令请求消息发送到的 AP 队列(NQAP 和 PQAP 指令),或从中接收命令回复消息的 AP 队列(DQAP 指令)。APQN 的有效性由从 APM 和 AQM 计算出的矩阵定义;它是所有分配的适配器编号 (APM) 与所有分配的队列索引 (AQM) 的笛卡尔积。例如,如果将适配器 1 和 2 以及使用域 5 和 6 分配给虚拟机,则 APQN (1,5)、(1,6)、(2,5) 和 (2,6) 将对虚拟机有效。
APQN 可以提供安全密钥功能——即,私钥存储在适配器卡上的每个域中——因此每个 APQN 最多必须分配给一个虚拟机或 Linux 主机
Example 1: Valid configuration:
------------------------------
Guest1: adapters 1,2 domains 5,6
Guest2: adapter 1,2 domain 7
This is valid because both guests have a unique set of APQNs:
Guest1 has APQNs (1,5), (1,6), (2,5), (2,6);
Guest2 has APQNs (1,7), (2,7)
Example 2: Valid configuration:
------------------------------
Guest1: adapters 1,2 domains 5,6
Guest2: adapters 3,4 domains 5,6
This is also valid because both guests have a unique set of APQNs:
Guest1 has APQNs (1,5), (1,6), (2,5), (2,6);
Guest2 has APQNs (3,5), (3,6), (4,5), (4,6)
Example 3: Invalid configuration:
--------------------------------
Guest1: adapters 1,2 domains 5,6
Guest2: adapter 1 domains 6,7
This is an invalid configuration because both guests have access to
APQN (1,6).
设计¶
该设计引入了三个新对象
AP 矩阵设备
VFIO AP 设备驱动程序 (vfio_ap.ko)
VFIO AP 调解的直通设备
VFIO AP 设备驱动程序¶
VFIO AP (vfio_ap) 设备驱动程序具有以下用途
提供接口来保护 APQN 以供 KVM 虚拟机独占使用。
设置 VFIO 调解的设备接口以管理 vfio_ap 调解的设备,并创建 sysfs 接口来分配构成 KVM 虚拟机矩阵的适配器、使用域和控制域。
在 KVM 虚拟机的 SIE 状态描述引用的 CRYCB 中包含的 APCB 中配置 APM、AQM 和 ADM,以授予虚拟机访问 AP 设备矩阵的权限
保留 APQN 以供 KVM 虚拟机独占使用¶
以下框图说明了保留 APQN 的机制
+------------------+
7 remove | |
+--------------------> cex4queue driver |
| | |
| +------------------+
|
|
| +------------------+ +----------------+
| 5 register driver | | 3 create | |
| +----------------> Device core +----------> matrix device |
| | | | | |
| | +--------^---------+ +----------------+
| | |
| | +-------------------+
| | +-----------------------------------+ |
| | | 4 register AP driver | | 2 register device
| | | | |
+--------+---+-v---+ +--------+-------+-+
| | | |
| ap_bus +--------------------- > vfio_ap driver |
| | 8 probe | |
+--------^---------+ +--^--^------------+
6 edit | | |
apmask | +-----------------------------+ | 11 mdev create
aqmask | | 1 modprobe |
+--------+-----+---+ +----------------+-+ +----------------+
| | | |10 create| mediated |
| admin | | VFIO device core |---------> matrix |
| + | | | device |
+------+-+---------+ +--------^---------+ +--------^-------+
| | | |
| | 9 create vfio_ap-passthrough | |
| +------------------------------+ |
+-------------------------------------------------------------+
12 assign adapter/domain/control domain
保留 AP 队列以供 KVM 虚拟机使用的过程是
管理员加载 vfio_ap 设备驱动程序
vfio-ap 驱动程序在初始化期间会向设备核心注册一个单独的“矩阵”设备。该设备将作为所有用于为虚拟机配置 AP 矩阵的 vfio_ap 调解设备的父设备。
设备核心创建 /sys/devices/vfio_ap/matrix 设备。
vfio_ap 设备驱动程序将向 AP 总线注册类型为 10 及更高版本(CEX4 及更新版本)的 AP 队列设备。驱动程序将提供 vfio_ap 驱动程序的探测和移除回调接口。不支持 CEX4 队列之前的较旧设备,这样做是为了简化实现,避免因支持在相对较近的未来会停止使用的较旧设备而无谓地复杂化设计,并且周围可用于测试的较旧系统也较少。
AP 总线向设备核心注册 vfio_ap 设备驱动程序。
管理员编辑 AP 适配器和队列掩码,以保留供 vfio_ap 设备驱动程序使用的 AP 队列。
AP 总线从默认的 zcrypt cex4queue 驱动程序中移除为 vfio_ap 驱动程序保留的 AP 队列。
AP 总线探测 vfio_ap 设备驱动程序以绑定为其保留的队列。
管理员创建一个透传类型的 vfio_ap 调解设备供虚拟机使用。
管理员分配适配器、使用域和控制域供虚拟机独占使用。
设置 VFIO 调解设备接口¶
VFIO AP 设备驱动程序利用 VFIO 调解设备核心驱动程序的通用接口来
注册一个 AP 调解总线驱动程序,以添加 vfio_ap 调解设备到 VFIO 组并从中删除它。
创建和销毁 vfio_ap 调解设备。
添加 vfio_ap 调解设备到 AP 调解总线驱动程序并从中删除它。
添加 vfio_ap 调解设备到 IOMMU 组并从中删除它。
以下高级框图显示了 VFIO AP 调解设备驱动程序的主要组件和接口。
+-------------+
| |
| +---------+ | mdev_register_driver() +--------------+
| | Mdev | +<-----------------------+ |
| | bus | | | vfio_mdev.ko |
| | driver | +----------------------->+ |<-> VFIO user
| +---------+ | probe()/remove() +--------------+ APIs
| |
| MDEV CORE |
| MODULE |
| mdev.ko |
| +---------+ | mdev_register_parent() +--------------+
| |Physical | +<-----------------------+ |
| | device | | | vfio_ap.ko |<-> matrix
| |interface| +----------------------->+ | device
| +---------+ | callback +--------------+
+-------------+
在 vfio_ap 模块初始化期间,矩阵设备注册一个 'mdev_parent_ops' 结构,该结构为管理调解矩阵设备提供 sysfs 属性结构、mdev 函数和回调接口。
sysfs 属性结构
- supported_type_groups
VFIO 调解设备框架支持创建用户定义的调解设备类型。这些调解设备类型在将设备注册到调解设备框架时通过 'supported_type_groups' 结构指定。注册过程为已注册设备 'mdev_supported_types' 子目录中指定的每个调解设备类型创建 sysfs 结构。连同设备类型,还会提供调解设备类型的 sysfs 属性。
VFIO AP 设备驱动程序将为透传设备注册一种调解设备类型。
/sys/devices/vfio_ap/matrix/mdev_supported_types/vfio_ap-passthrough
仅提供 VFIO mdev 框架所需的只读属性。
... name ... device_api ... available_instances ... device_api
其中
- name
指定调解设备类型的名称。
- device_api
调解设备类型的 API。
- available_instances
可以创建的 vfio_ap 调解透传设备的数量。
- device_api
指定 VFIO API。
- mdev_attr_groups
此属性组标识调解设备的用户定义的 sysfs 属性。当设备注册到 VFIO 调解设备框架时,在 'mdev_attr_groups' 结构中标识的 sysfs 属性文件将在 vfio_ap 调解设备的目录中创建。vfio_ap 调解设备的 sysfs 属性为:
- assign_adapter / unassign_adapter
用于向/从 vfio_ap 调解设备分配/取消分配 AP 适配器的只写属性。要分配/取消分配适配器,适配器的 APID 会被回显到相应的属性文件中。
- assign_domain / unassign_domain
用于向/从 vfio_ap 调解设备分配/取消分配 AP 使用域的只写属性。要分配/取消分配域,使用域的域号会被回显到相应的属性文件中。
- matrix
一个只读文件,用于显示从分配给 vfio_ap 调解设备的适配器和域号的笛卡尔积派生的 APQN。
- guest_matrix
一个只读文件,用于显示从分配给 KVM 虚拟机 CRYCB 的 APM 和 AQM 字段的适配器和域号的笛卡尔积派生的 APQN。如果任何 APQN 未引用绑定到 vfio_ap 设备驱动程序的队列设备(即,队列不在主机的 AP 配置中),则它可能与分配给 vfio_ap 调解设备的 APQN 不同。
- assign_control_domain / unassign_control_domain
用于向/从 vfio_ap 调解设备分配/取消分配 AP 控制域的只写属性。要分配/取消分配控制域,要分配/取消分配的域的 ID 会被回显到相应的属性文件中。
- control_domains
一个只读文件,用于显示分配给 vfio_ap 调解设备的控制域号。
- ap_config
一个读/写文件,写入时,允许一次性替换 vfio_ap 调解设备的所有三个 ap 矩阵掩码。给出三个掩码,一个用于适配器,一个用于域,一个用于控制域。如果无法设置给定的状态,则不会对 vfio-ap 调解设备进行任何更改。
写入 ap_config 的数据的格式如下:{amask},{dmask},{cmask}n
n 是一个换行符。
amask、dmask 和 cmask 是标识哪些适配器、域和控制域应分配给调解设备的掩码。
掩码的格式如下:0xNN..NN
其中 NN..NN 是 64 个十六进制字符,表示一个 256 位值。最左边(最高位)的位表示适配器/域 0。
对于表示您的 mdev 当前配置的掩码示例集,只需 cat ap_config 即可。
设置大于系统允许的最大值的适配器或域号将导致错误。
此属性旨在供自动化使用。最终用户最好使用适配器、域和控制域的相应分配/取消分配属性。
functions
- create
分配 vfio_ap 驱动程序使用的 ap_matrix_mdev 结构,以
存储使用 mdev 的虚拟机的 KVM 结构的引用。
存储通过相应 sysfs 属性文件分配的适配器、域和控制域的 AP 矩阵配置。
存储可供虚拟机使用的适配器、域和控制域的 AP 矩阵配置。虚拟机可能无法访问引用不存在或未绑定到 vfio_ap 设备驱动程序的队列设备的 APQN。
- remove
释放 vfio_ap 调解设备的 ap_matrix_mdev 结构。只有在正在运行的虚拟机未使用 mdev 时才允许这样做。
callback interfaces
- open_device
vfio_ap 驱动程序使用此回调为矩阵 mdev 设备注册 VFIO_GROUP_NOTIFY_SET_KVM 通知器回调函数。open_device 回调由用户空间调用,以将矩阵 mdev 设备的 VFIO iommu 组连接到 MDEV 总线。可以通过此回调访问用于配置 KVM 虚拟机的 KVM 结构。KVM 结构用于配置虚拟机对通过 vfio_ap 调解设备的 sysfs 属性文件定义的 AP 矩阵的访问。
- close_device
取消注册矩阵 mdev 设备的 VFIO_GROUP_NOTIFY_SET_KVM 通知器回调函数,并取消配置虚拟机的 AP 矩阵。
- ioctl
此回调处理 vfio 框架定义的 VFIO_DEVICE_GET_INFO 和 VFIO_DEVICE_RESET ioctl。
配置虚拟机的 AP 资源¶
当调用 VFIO_GROUP_NOTIFY_SET_KVM 通知器回调时,将为 KVM 虚拟机配置 AP 资源。当用户空间连接到 KVM 时,将调用通知器函数。虚拟机的 AP 资源通过其 APCB 配置,方法是:
设置 APM 中与通过其 'assign_adapter' 接口分配给 vfio_ap 调解设备的 APID 对应的位。
设置 AQM 中与通过其 'assign_domain' 接口分配给 vfio_ap 调解设备的域对应的位。
设置 ADM 中与通过其 'assign_control_domains' 接口分配给 vfio_ap 调解设备的域 dID 对应的位。
Linux 设备模型禁止将未绑定到促进其透传的设备驱动程序的设备传递给 KVM 虚拟机。因此,不引用绑定到 vfio_ap 设备驱动程序的队列设备的 APQN 将不会分配给 KVM 虚拟机的矩阵。但是,AP 体系结构不提供从虚拟机的矩阵中过滤单个 APQN 的方法,因此在向虚拟机提供 AP 配置之前,将过滤通过其 sysfs 'assign_adapter'、'assign_domain' 和 'assign_control_domain' 接口分配给 vfio_ap 调解设备的适配器、域和控制域。
将过滤分配给矩阵 mdev 但也未分配给主机 AP 配置的适配器的 APID、域的 APQI 和控制域的域号。
检查从分配给 vfio_ap mdev 的 APID 和 APQI 的笛卡尔积派生的每个 APQN,如果其中任何一个 APQN 未引用绑定到 vfio_ap 设备驱动程序的队列设备,则该适配器将不会插入到虚拟机中(即,其 APID 对应的位将不会在虚拟机的 APCB 的 APM 中设置)。
AP 的 CPU 模型特性¶
AP 堆栈依赖于 AP 指令的存在以及三个功能:AP 功能测试 (APFT) 功能;AP 查询配置信息 (QCI) 功能;以及 AP 队列中断控制功能。这些特性/功能通过以下 CPU 模型特性提供给 KVM 虚拟机:
ap:指示是否在虚拟机上安装了 AP 指令。仅当主机上安装了 AP 指令时,KVM 才会启用此特性。
apft:指示虚拟机上是否可用 APFT 功能。仅当主机上可用此功能时(即,设置了功能位 15),此功能才可供虚拟机使用。
apqci:指示虚拟机上是否可用 AP QCI 功能。仅当主机上可用此功能时(即,设置了功能位 12),此功能才可供虚拟机使用。
apqi:指示虚拟机上是否可用 AP 队列中断控制功能。仅当主机上可用此功能时(即,设置了功能位 65),此功能才可供虚拟机使用。
注意:如果用户选择向 QEMU 指定与“host”模型不同的 CPU 模型,则需要显式启用 CPU 模型特性和功能;例如
/usr/bin/qemu-system-s390x ... -cpu z13,ap=on,apqci=on,apft=on,apqi=on
可以通过显式关闭 AP 特性/功能来阻止虚拟机使用它们;例如
/usr/bin/qemu-system-s390x ... -cpu host,ap=off,apqci=off,apft=off,apqi=off
注意:如果为虚拟机关闭了 APFT 功能 (apft=off),则虚拟机将看不到任何 AP 设备。虚拟机上为类型 10 及更高版本 AP 设备注册的 zcrypt 设备驱动程序(即 cex4card 和 cex4queue 设备驱动程序)需要 APFT 功能来确定给定 AP 设备上安装的功能。如果虚拟机上未安装 APFT 功能,则在虚拟机上运行的 AP 总线将不会创建任何适配器或域设备,因为只有类型 10 及更高版本的设备才能配置为供虚拟机使用。
示例¶
现在提供一个示例来说明如何向 KVM 虚拟机授予对 AP 功能的访问权限。在此示例中,我们将展示如何配置三个虚拟机,以便在虚拟机上执行 lszcrypt 命令看起来像这样:
Guest1¶
CARD.DOMAIN |
TYPE |
MODE |
---|---|---|
05 |
CEX5C |
CCA-Coproc |
05.0004 |
CEX5C |
CCA-Coproc |
05.00ab |
CEX5C |
CCA-Coproc |
06 |
CEX5A |
Accelerator |
06.0004 |
CEX5A |
Accelerator |
06.00ab |
CEX5A |
Accelerator |
访客 2¶
CARD.DOMAIN |
TYPE |
MODE |
---|---|---|
05 |
CEX5C |
CCA-Coproc |
05.0047 |
CEX5C |
CCA-Coproc |
05.00ff |
CEX5C |
CCA-Coproc |
访客 3¶
CARD.DOMAIN |
TYPE |
MODE |
---|---|---|
06 |
CEX5A |
Accelerator |
06.0047 |
CEX5A |
Accelerator |
06.00ff |
CEX5A |
Accelerator |
以下是步骤
在 Linux 主机上安装 vfio_ap 模块。vfio_ap 模块的依赖链是:* iommu * s390 * zcrypt * vfio * vfio_mdev * vfio_mdev_device * KVM
要构建 vfio_ap 模块,内核构建必须配置为选择以下 Kconfig 元素:* IOMMU_SUPPORT * S390 * AP * VFIO * KVM
如果使用 make menuconfig,请选择以下选项来构建 vfio_ap 模块
-> Device Drivers -> IOMMU Hardware Support select S390 AP IOMMU Support -> VFIO Non-Privileged userspace driver framework -> Mediated device driver frramework -> VFIO driver for Mediated devices -> I/O subsystem -> VFIO support for AP devices
保护三个访客将要使用的 AP 队列,使主机无法访问它们。要保护它们,有两个 sysfs 文件指定位掩码,将 APQN 范围的子集标记为只能由默认的 AP 队列设备驱动程序使用。所有剩余的 APQN 都可供任何其他设备驱动程序使用。vfio_ap 设备驱动程序目前是唯一的非默认设备驱动程序。包含掩码的 sysfs 文件的位置是
/sys/bus/ap/apmask /sys/bus/ap/aqmask
“apmask”是一个 256 位掩码,用于标识一组 AP 适配器 ID (APID)。掩码中的每一位(从左到右)对应于 APID 0-255。如果设置了某个位,则 APID 属于标记为仅可供默认 AP 队列设备驱动程序使用的 APQN 子集。
“aqmask”是一个 256 位掩码,用于标识一组 AP 队列索引 (APQI)。掩码中的每一位(从左到右)对应于 APQI 0-255。如果设置了某个位,则 APQI 属于标记为仅可供默认 AP 队列设备驱动程序使用的 APQN 子集。
APID 的笛卡尔积(对应于 apmask 中设置的位)和 APQI 的笛卡尔积(对应于 aqmask 中设置的位)构成 APQN 的子集,该子集只能由主机默认设备驱动程序使用。所有其他 APQN 都可供非默认设备驱动程序(如 vfio_ap 驱动程序)使用。
例如,考虑以下掩码
apmask: 0x7d00000000000000000000000000000000000000000000000000000000000000 aqmask: 0x8000000000000000000000000000000000000000000000000000000000000000
这些掩码指示
适配器 1、2、3、4、5 和 7 可供主机默认设备驱动程序使用。
域 0 可供主机默认设备驱动程序使用
仅可供默认主机设备驱动程序使用的 APQN 子集为
(1,0)、(2,0)、(3,0)、(4.0)、(5,0) 和 (7,0)
所有其他 APQN 都可供非默认设备驱动程序使用。
分配给 Linux 主机的每个 AP 队列设备的 APQN 都由 AP 总线检查,以确定是否与从 APID 和 APQI 的笛卡尔积导出的 APQN 集匹配,这些 APQN 被标记为可供默认 AP 队列设备驱动程序使用。如果检测到匹配,则只会探测默认的 AP 队列设备驱动程序;否则,将探测 vfio_ap 设备驱动程序。
默认情况下,这两个掩码设置为保留所有 APQN,以供默认的 AP 队列设备驱动程序使用。可以通过两种方式更改默认掩码
可以通过将字符串回显到两个格式中的一个中来编辑 sysfs 掩码文件
以 0x 开头的绝对十六进制字符串(例如“0x12345678”)设置掩码。如果给定的字符串比掩码短,则会在右侧填充 0;例如,指定掩码值 0x41 与指定相同
0x4100000000000000000000000000000000000000000000000000000000000000
请记住,掩码从左到右读取,因此上面的掩码标识设备号 1 和 7 (01000001)。
如果字符串比掩码长,则操作将终止并出现错误 (EINVAL)。
可以通过在逗号分隔的列表中指定要切换的每个位号来打开和关闭掩码中的单个位。每个位号字符串必须以 ('+') 或减号 ('-') 作为前缀,以指示相应的位将被打开 ('+') 或关闭 ('-')。一些有效的值是
“+0”打开位 0
“-13”关闭位 13
“+0x41”打开位 65
“-0xff”关闭位 255
以下示例
+0,-6,+0x47,-0xf0
打开位 0 和 71 (0x47)
关闭位 6 和 240 (0xf0)
请注意,列表中未指定的位将保持操作之前的状态。
也可以在引导时通过内核命令行上的参数更改掩码,如下所示
ap.apmask=0xffff ap.aqmask=0x40
这将创建以下掩码
apmask: 0xffff000000000000000000000000000000000000000000000000000000000000 aqmask: 0x4000000000000000000000000000000000000000000000000000000000000000
导致这两个池
default drivers pool: adapter 0-15, domain 1 alternate drivers pool: adapter 16-255, domains 0, 2-255
注意:更改掩码,使一个或多个 APQN 将从 vfio_ap 介导的设备(见下文)中获取,将会失败并出现错误 (EBUSY)。消息记录到内核环形缓冲区,可以使用“dmesg”命令查看。输出标识标记为“正在使用”的每个 APQN,并标识分配给它的 vfio_ap 介导的设备;例如
用户空间可能无法重新分配已分配给 62177883-f1bb-47f0-914d-32a22e3a8804 的队列 05.0054,用户空间可能无法重新分配已分配给 cef03c3c-903d-4ecc-9a83-40694cb8aee4 的队列 04.0054
为我们的示例保护 APQN¶
要保护 AP 队列 05.0004、05.0047、05.00ab、05.00ff、06.0004、06.0047、06.00ab 和 06.00ff 以供 vfio_ap 设备驱动程序使用,可以使用以下命令之一从默认掩码中删除相应的 APQN
echo -5,-6 > /sys/bus/ap/apmask echo -4,-0x47,-0xab,-0xff > /sys/bus/ap/aqmask或者,可以将掩码设置为如下所示
echo 0xf9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ > apmask echo 0xf7fffffffffffffffeffffffffffffffffffffffffeffffffffffffffffffffe \ > aqmask这将导致 AP 队列 05.0004、05.0047、05.00ab、05.00ff、06.0004、06.0047、06.00ab 和 06.00ff 绑定到 vfio_ap 设备驱动程序。vfio_ap 设备驱动程序的 sysfs 目录现在将包含指向绑定到它的 AP 队列设备的符号链接
/sys/bus/ap ... [drivers] ...... [vfio_ap] ......... [05.0004] ......... [05.0047] ......... [05.00ab] ......... [05.00ff] ......... [06.0004] ......... [06.0047] ......... [06.00ab] ......... [06.00ff]请记住,只有类型 10 及更新的适配器(即 CEX4 及更高版本)才能绑定到 vfio_ap 设备驱动程序。这样做的原因是,通过不为支持相对较短的时间内将停止使用的旧设备,以及很少有旧系统可供测试而无需不必要地复杂化设计,来简化实现。
因此,管理员必须小心,只保护可以绑定到 vfio_ap 设备驱动程序的 AP 队列。给定 AP 队列设备的设备类型可以从父卡的 sysfs 目录中读取。例如,要查看队列 05.0004 的硬件类型
cat /sys/bus/ap/devices/card05/hwtype
hwtype 必须为 10 或更高(CEX4 或更新版本),才能绑定到 vfio_ap 设备驱动程序。
创建配置三个访客的 AP 矩阵所需的中间设备,并为访客提供与 vfio_ap 驱动程序的接口
/sys/devices/vfio_ap/matrix/ --- [mdev_supported_types] ------ [vfio_ap-passthrough] (passthrough vfio_ap mediated device type) --------- create --------- [devices]
要为三个访客创建中间设备
uuidgen > create uuidgen > create uuidgen > create or echo $uuid1 > create echo $uuid2 > create echo $uuid3 > create
这将在名为写入 create 属性文件的 UUID 的 [devices] 子目录中创建三个中间设备。我们称它们为 $uuid1、$uuid2 和 $uuid3,这是创建后的 sysfs 目录结构
/sys/devices/vfio_ap/matrix/ --- [mdev_supported_types] ------ [vfio_ap-passthrough] --------- [devices] ------------ [$uuid1] --------------- assign_adapter --------------- assign_control_domain --------------- assign_domain --------------- matrix --------------- unassign_adapter --------------- unassign_control_domain --------------- unassign_domain ------------ [$uuid2] --------------- assign_adapter --------------- assign_control_domain --------------- assign_domain --------------- matrix --------------- unassign_adapter ----------------unassign_control_domain ----------------unassign_domain ------------ [$uuid3] --------------- assign_adapter --------------- assign_control_domain --------------- assign_domain --------------- matrix --------------- unassign_adapter ----------------unassign_control_domain ----------------unassign_domain
- 注意 *:除非使用
mdevctl 工具创建并持久化 vfio_ap mdev,否则它们不会在重启后保留。
管理员现在需要为中间设备 $uuid1(适用于访客 1)、$uuid2(适用于访客 2)和 $uuid3(适用于访客 3)配置矩阵。
这是为访客 1 配置矩阵的方式
echo 5 > assign_adapter echo 6 > assign_adapter echo 4 > assign_domain echo 0xab > assign_domain
可以使用 assign_control_domain sysfs 文件类似地分配控制域。
如果在配置适配器、域或控制域时出错,可以使用 unassign_xxx 文件来取消分配适配器、域或控制域。
要显示访客 1 的矩阵配置
cat matrix
要显示分配给访客 1 或将要分配给访客 1 的矩阵
cat guest_matrix
这是为访客 2 配置矩阵的方式
echo 5 > assign_adapter echo 0x47 > assign_domain echo 0xff > assign_domain
这是为访客 3 配置矩阵的方式
echo 6 > assign_adapter echo 0x47 > assign_domain echo 0xff > assign_domain
为了成功分配适配器
指定的适配器号必须表示从 0 到为系统配置的最大适配器号的值。如果指定的适配器号高于最大值,则操作将终止并出现错误 (ENODEV)。
- 注意:最大适配器号可以通过 sysfs
/sys/bus/ap/ap_max_adapter_id 属性文件获得。
从正在分配的适配器的 APID 和先前分配的域的 APQI 的笛卡尔积导出的每个 APQN
必须仅可供 sysfs /sys/bus/ap/apmask 和 /sys/bus/ap/aqmask 属性文件中指定的 vfio_ap 设备驱动程序使用。如果甚至有一个 APQN 保留供主机设备驱动程序使用,则操作将终止并出现错误 (EADDRNOTAVAIL)。
不得分配给另一个 vfio_ap 介导的设备。如果甚至有一个 APQN 分配给另一个 vfio_ap 介导的设备,则操作将终止并出现错误 (EBUSY)。
不得在编辑 sysfs /sys/bus/ap/apmask 和 sys/bus/ap/aqmask 属性文件时分配,否则操作可能会终止并出现错误 (EBUSY)。
为了成功分配域
指定的域号必须表示从 0 到为系统配置的最大域号的值。如果指定的域号高于最大值,则操作将终止并出现错误 (ENODEV)。
- 注意:最大域号可以通过 sysfs
/sys/bus/ap/ap_max_domain_id 属性文件获得。
从正在分配的域的 APQI 和先前分配的适配器的 APID 的笛卡尔积导出的每个 APQN
必须仅可供 sysfs /sys/bus/ap/apmask 和 /sys/bus/ap/aqmask 属性文件中指定的 vfio_ap 设备驱动程序使用。如果甚至有一个 APQN 保留供主机设备驱动程序使用,则操作将终止并出现错误 (EADDRNOTAVAIL)。
不得分配给另一个 vfio_ap 介导的设备。如果甚至有一个 APQN 分配给另一个 vfio_ap 介导的设备,则操作将终止并出现错误 (EBUSY)。
不得在编辑 sysfs /sys/bus/ap/apmask 和 sys/bus/ap/aqmask 属性文件时分配,否则操作可能会终止并出现错误 (EBUSY)。
为了成功分配控制域
指定的域号必须表示从 0 到为系统配置的最大域号的值。如果指定的控制域号高于最大值,则操作将终止并出现错误 (ENODEV)。
启动访客 1
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \ -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid1 ...
启动访客 2
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \ -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid2 ...
启动访客 3
/usr/bin/qemu-system-s390x ... -cpu host,ap=on,apqci=on,apft=on,apqi=on \ -device vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/$uuid3 ...
当访客关闭时,可以删除 vfio_ap 介导的设备。
再次使用我们的示例,要删除 vfio_ap 介导的设备 $uuid1
/sys/devices/vfio_ap/matrix/
--- [mdev_supported_types]
------ [vfio_ap-passthrough]
--------- [devices]
------------ [$uuid1]
--------------- remove
echo 1 > remove
这将删除所有矩阵 mdev 设备的 sysfs 结构,包括 mdev 设备本身。要重新创建和重新配置矩阵 mdev 设备,必须再次执行从步骤 3 开始的所有步骤。请注意,如果使用 vfio_ap mdev 的访客仍在运行,则删除将失败。
不必删除 vfio_ap mdev,但如果 Linux 主机的剩余生命周期内没有访客会使用它,则可能需要删除它。如果删除了 vfio_ap mdev,则可能还需要重新配置为默认驱动程序预留的适配器和队列池。
热插拔支持:¶
如果满足以下条件,则可以通过将其分配给访客使用的 vfio_ap 介导的设备,将适配器、域或控制域热插拔到正在运行的 KVM 访客中
适配器、域或控制域还必须分配给主机的 AP 配置。
从由正在分配的适配器的 APID 和分配的域的 APQI 组成的笛卡尔积导出的每个 APQN 都必须引用绑定到 vfio_ap 设备驱动程序的队列设备。
要热插拔一个域,每个由被分配域的 APQI 和被分配适配器的 APID 的笛卡尔积导出的 APQN,必须引用一个绑定到 vfio_ap 设备驱动程序的队列设备。
可以通过取消分配一个适配器、域或控制域到虚拟机所使用的 vfio_ap 中介设备来从正在运行的 KVM 虚拟机中热拔插它们。
为 KVM 虚拟机过度配置 AP 队列:¶
本文中,过度配置定义为将适配器或域分配给 vfio_ap 中介设备,而这些适配器或域在主机的 AP 配置中没有引用 AP 设备。这里的想法是,当适配器或域可用时,只要插入它产生的每个新 APQN 都引用一个绑定到 vfio_ap 设备驱动程序的队列设备,它就会自动热插拔到 KVM 虚拟机中,使用分配给它的 vfio_ap 中介设备。
驱动程序特性¶
vfio_ap 驱动程序公开一个包含支持特性的 sysfs 文件。此文件的存在是为了让第三方工具(如 Libvirt 和 mdevctl)可以查询特定特性的可用性。
特性列表可以在这里找到:/sys/bus/matrix/devices/matrix/features
条目用空格分隔。每个条目由字母数字和下划线字符的组合组成。
示例:cat /sys/bus/matrix/devices/matrix/features guest_matrix dyn ap_config
以下是所声明的特性
---------------+---------------------------------------------------------------+ | 标志 | 描述 | +==============+===============================================================+ | guest_matrix | 存在 guest_matrix 属性。它报告当 mdev 连接到虚拟机时 | | | 将传递给虚拟机的适配器和域的矩阵。 | +--------------+---------------------------------------------------------------+ | dyn | 指示连接到 mdev 的虚拟机的 AP 适配器、域和控制域的 | | | 热插拔/热拔出。 | +------------+-----------------------------------------------------------------+ | ap_config | 用于对 mdev 配置进行一次性修改的 ap_config 接口 | +--------------+---------------------------------------------------------------+
限制¶
对于使用 AP 设备的虚拟机,在没有系统管理员干预的情况下不支持实时虚拟机迁移。在可以迁移 KVM 虚拟机之前,必须移除 vfio_ap 中介设备。不幸的是,当 mdev 被 KVM 虚拟机使用时,不能手动移除它(即,echo 1 > /sys/devices/vfio_ap/matrix/$UUID/remove)。如果虚拟机由 QEMU 模拟,可以通过以下两种方式之一从虚拟机热拔出 mdev
如果 KVM 虚拟机是使用 libvirt 启动的,您可以通过以下命令热拔出 mdev
virsh detach-device <虚拟机名称> <设备 XML 文件的路径>
例如,要从名为 “my-guest” 的虚拟机热拔出 mdev 62177883-f1bb-47f0-914d-32a22e3a8804
virsh detach-device my-guest ~/config/my-guest-hostdev.xml
my-guest-hostdev.xml 的内容
<hostdev mode='subsystem' type='mdev' managed='no' model='vfio-ap'>
<source>
<address uuid='62177883-f1bb-47f0-914d-32a22e3a8804'/>
</source>
</hostdev>
virsh qemu-monitor-command <guest-name> --hmp "device-del <device-id>"
For example, to hot unplug the vfio_ap mediated device identified on the
qemu command line with 'id=hostdev0' from the guest named 'my-guest':
virsh qemu-monitor-command my-guest --hmp "device_del hostdev0"
可以通过将 qemu 监视器连接到虚拟机并使用以下 qemu 监视器命令来热拔出 vfio_ap 中介设备
(QEMU) device-del id=<设备 ID>
例如,要热拔出在虚拟机启动时使用 “id=hostdev0” 在 qemu 命令行上指定的 vfio_ap 中介设备
(QEMU) device-del id=hostdev0
在完成 KVM 虚拟机的实时迁移后,可以通过以下两种方式之一将 AP 配置恢复到 KVM 虚拟机,方法是在目标系统上将 vfio_ap 中介设备热插拔到虚拟机中
如果 KVM 虚拟机是使用 libvirt 启动的,您可以通过以下 virsh 命令将 matrix 中介设备热插拔到虚拟机中
virsh attach-device <虚拟机名称> <设备 XML 文件的路径>
例如,要将 mdev 62177883-f1bb-47f0-914d-32a22e3a8804 热插拔到名为 “my-guest” 的虚拟机中
virsh attach-device my-guest ~/config/my-guest-hostdev.xml
my-guest-hostdev.xml 的内容
<hostdev mode='subsystem' type='mdev' managed='no' model='vfio-ap'>
<source>
<address uuid='62177883-f1bb-47f0-914d-32a22e3a8804'/>
</source>
</hostdev>
virsh qemu-monitor-command <guest-name> --hmp \
"device_add vfio-ap,sysfsdev=<path-to-mdev>,id=<device-id>"
For example, to hot plug the vfio_ap mediated device
62177883-f1bb-47f0-914d-32a22e3a8804 into the guest named 'my-guest' with
device-id hostdev0:
virsh qemu-monitor-command my-guest --hmp \
"device_add vfio-ap,\
sysfsdev=/sys/devices/vfio_ap/matrix/62177883-f1bb-47f0-914d-32a22e3a8804,\
id=hostdev0"
可以通过将 qemu 监视器连接到虚拟机并使用以下 qemu 监视器命令来热插拔 vfio_ap 中介设备
(qemu) device_add “vfio-ap,sysfsdev=<mdev 的路径>,id=<设备 ID>”
例如,要将 vfio_ap 中介设备 62177883-f1bb-47f0-914d-32a22e3a8804 插入到虚拟机中,设备 ID 为 hostdev0
(QEMU) device-add “vfio-ap,sysfsdev=/sys/devices/vfio_ap/matrix/62177883-f1bb-47f0-914d-32a22e3a8804,id=hostdev0”