kvm API 接口就是一组 ioctl 集合,用来控制虚拟机的各个方面。这些 ioctl 可以分为四类:
kvm API 以文件描述符为中心。
通过 open("/dev/kvm") 获得 kvm 子系统的句柄;此句柄可用于调用系统 ioctl。通过调用ioctl KVM_CREATE_VM 将创建一个 VM 文件描述符,该描述符可用于发出 VM ioctl(第二类 ioctl)。 VM fd 上的 KVM_CREATE_VCPU 或 KVM_CREATE_DEVICE ioctl 将创建一个虚拟 cpu 或虚拟设备 device,并返回对应的文件描述符。使用 vcpu 或 device fd 可以执行对应的 ioctl (第三类,四类 ioctl)。
需要注意的是,虽然 VM ioctl 只能从创建 VM 的进程发出,但 VM 的生命周期与其文件描述符相关联,而不是与其创建者(进程)相关联。换句话说,直到最后一个对 VM 文件描述符的引用被释放后,VM 及其资源(包括相关的地址空间)才会被释放。例如,如果在 ioctl(KVM_CREATE_VM) 之后发出 fork(),则在父(原始)进程及其子进程都将其引用 VM 的文件描述符释放后,才会释放 VM资源。
由于必须释放文件描述符的所有饮用才会释放 VM 资源,因此强烈建议不要轻易通过 fork()、dup() 等创建 VM 的引用,这可能会产生不必要的副作用,例如当虚拟机关闭时,由虚拟机进程分配的内存可能不会被释放/取消。
从 Linux 2.6.22 开始,KVM ABI 已经稳定:不允许向后不兼容的更改。但是,有一个扩展工具允许查询和使用 API 的向后兼容扩展。
扩展机制不基于 Linux 版本号。相反,kvm 定义了扩展标识符和一个查询特定扩展标识符是否可用的工具。如果是,则对应的 ioctl 是可用的。
本节介绍 kvm guest 的 ioctl api。对于每个 ioctl,都提供了以下信息和描述:
guest 与 host: 一般来说,host 是虚拟机的宿主机,对虚拟机进行管理,而 guest 即虚拟机,这个是相当host 的一个概念。
ENOTTYEBADF, ENOMEM, EINVAL获取当前 kvm 的接口版本
Capability:basic
Architectures:all
Type:system ioctl
Parameters:none
Returns:the constant KVM_API_VERSION (=12)
这个ioctl的返回值预期就是12,如果返回值为12,说明这个是符合预期的,所有 Capability 为 basic 的 ioctl 都是可用的。
创建虚拟机
Capability:basic
Architectures:all
Type:system ioctl
Parameters:machine type identifier (KVM_VM_*)
Returns:a VM fd that can be used to control the new virtual machine.
如果我们想先创建一个即没有虚拟 CPU,也没有内存的虚拟机,那可以使用 0 作为机器类型。
如果是在 S390 上创建虚拟机,请先执行 KVM_CAP_S390_UCONTROL检查,并使用标志 `KVM_VM_S390_UCONTROL` 作为特权用户。
这里标注 KVM_CREATE_VM 是一种 basic 能力,实际在 s390 上不一定是100%支持的,如果在 s390 上使用, 需要执行 KVM_CAP_S390_UCONTROL 进行检查。
在 arm64 上,VM 的物理地址大小(IPA 大小限制)默认限制为 40 位(即 1TB )。如果主机支持扩展 KVM_CAP_ARM_VM_IPA_SIZE,则可以配置限制。如果支持,请使用 KVM_VM_TYPE_ARM_IPA_SIZE(IPA_Bits) 设置机器类型标识符中的大小.
例如已知某arm单板支持 KVM_CAP_ARM_VM_IPA_SIZE, 则可以通过以下方式设置虚拟机内存寻址大小
- dev_fd= open("/dev/kvm");
-
- vm_fd = ioctl(dev_fd, KVM_CREATE_VM, KVM_VM_TYPE_ARM_IPA_SIZE(48));
如果配置的 IPA_SIZE 大小是不被支持的,则 create vm将失败。
Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
Architectures:x86
Type:system ioctl
Parameters:struct kvm_msr_list (in/out)
Returns:0 on success; -1 on error
Errors:
| EFAULT | 无法读取或写入 msr 索引列表 |
|---|---|
| E2BIG | msr 索引太大,无法放入用户指定的数组中。 |
- struct kvm_msr_list {
- __u32 nmsrs; /* number of msrs in entries */
- __u32 indices[0];
- };
用户在 nmsrs 中填写索引数组的大小, kvm 调整 nmsrs 以反映 msrs 的实际数量,并用它们的数字填充索引数组。
查询当前内核对 kvm API 的扩展支持。
Capability: basic, KVM_CAP_CHECK_EXTENSION_VM for vm ioctl
Architectures: all
Type: system ioctl, vm ioctl
Parameters: extension identifier (KVM_CAP_*)
Returns: 0 表示不支持; 1或其它数字表示支持
其参数为一个扩展标识符KVM_CAP_*, 返回0表示不支持, 1或其它数表示支持。
获取 vcpu 的控制内存区域大小。
KVM_RUN ioctl 通过共享内存区域与用户空间通信。此 ioctl 返回该区域的大小。
Capability:basic
Architectures: all
Type:system ioctl
Parameters:none
Returns:size of vcpu mmap area, in bytes
此内存空间是用户可以控制的 vcpu 内存。其与cpu构架是无关的,所以这是个 system ioctl, 我们调用 ioctl 时需要穿入dev_fd,而不是vcpu_fd
除了 KVM_RUN 通信区域的大小, 此接口返回的 mmap 还包含了VCPU 文件描述符的其他区域,如:
KVM_CAP_COALESCED_MMIO 是可用的,则内存页 KVM_COALESCED_MMIO_PAGE_OFFSET * PAGE_SIZE 也包含在此 mmap 内存区域内。KVM_CAP_DIRTY_LOG_RING 是可用的,则 KVM_DIRTY_LOG_PAGE_OFFSET * PAGE_SIZE 的一些页也是在该 mmap 内存区域,8.3 节有更详细的描述。此 ioctl 已过时并已删除
Capability:basic
Architectures:all
Type:vm ioctl
Parameters:struct kvm_memory_region (in)
Returns:0 on success, -1 on error
创建 vcpu
Capability: basic
Architectures: all
Type: vm ioctl
Parameters: vcpu id (apic id on x86)
Returns: vcpu fd on success, -1 on error
新增一个 vcpu 到虚拟机。最多可以添加 max_vcpus。 vcpu id 是 [0, max_vcpu_id) 范围内的整数。
可以在运行时使用 KVM_CHECK_EXTENSION ioctl, 传入参数 KVM_CAP_NR_VCPUS, 返回推荐的 max_vcpus 值。传入参数 KVM_CAP_MAX_VCPUS, 返回最大可能的 max_vcpus 值。
如果 KVM_CAP_NR_VCPUS 不存在,您应该假设 max_vcpus 为 4, 如果 KVM_CAP_MAX_VCPUS 不存在,您应该假设 max_vcpus 与 KVM_CAP_NR_VCPUS 返回的值相同.
可以在运行时使用 KVM_CHECK_EXTENSION ioctl, 传入参数 KVM_CAP_MAX_VCPU_ID , 获取 max_vcpu_id 的最大可能值。
获取所有脏页的位图
Capability:basic
Architectures:all
Type:vm ioctl
Parameters:struct kvm_dirty_log (in/out)
Returns:0 on success, -1 on error
给定一个 memory solt,返回自上次调用此 ioctl 以来所有脏页的位图。位 0 是内存插槽中的第一页。
(免费订阅,永久学习)学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂
更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,永久学习,或点击这里加qun免费
领取,关注我持续更新哦! !
(确保清除整个 kvm_dirty_log 以避免填充问题)
- /* for KVM_GET_DIRTY_LOG */
- struct kvm_dirty_log {
- __u32 slot;
- __u32 padding;
- union {
- void __user *dirty_bitmap; /* one bit per page */
- __u64 padding;
- };
- };
如果 KVM_CAP_MULTI_ADDRESS_SPACE 可用,slot 字段的第 16-31 位指定要返回脏位图的地址空间。有关 slot 字段使用的详细信息,请参阅 KVM_SET_USER_MEMORY_REGION。
此 ioctl 已过时并已被删除。
运行 guest vcpu。
Capability: basic
Architectures: all
Type: vcpu ioctl
Parameters: none
Returns: 0 on success, -1 on error
虽然该接口没有显示指定参数,但是需要我们事先配置好 struct kvm_run
获取CPU的通用寄存器信息,参数 struct kvm_regs, 该接口不支持 arm64 构架
Capability: basic
Architectures: all except arm64
Type: vcpu ioctl
Parameters: struct kvm_regs (out)
Returns: 0 on success, -1 on error
Reads the general purpose registers from the vcpu.
- /* x86 */
- struct kvm_regs {
- /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
- __u64 rax, rbx, rcx, rdx;
- __u64 rsi, rdi, rsp, rbp;
- __u64 r8, r9, r10, r11;
- __u64 r12, r13, r14, r15;
- __u64 rip, rflags;
- };
-
- /* mips */
- struct kvm_regs {
- /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
- __u64 gpr[32];
- __u64 hi;
- __u64 lo;
- __u64 pc;
- };
设置CPU的通用寄存器信息,参数 struct kvm_regs, 该接口不支持 arm64 构架
Capability: basic
Architectures: all except arm64
Type: vcpu ioctl
Parameters: struct kvm_regs (in)
Returns: 0 on success, -1 on error
Writes the general purpose registers into the vcpu.
See KVM_GET_REGS for the data structure.