4

StratoVirt代码分析

 3 years ago
source link: https://my.oschina.net/u/4612860/blog/4877928
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

StratoVirt代码分析

  1. 功能

StraoVirt当前的主要功能是能够创建一个microVM。该虚拟机提供了一个沙箱功能,为在其上运行的其他应用提供了一层安全隔离。弥补了docker在安全性上的不足。

  1. 代码解析

下图是当前StratoVirt的主流程。主要分为以下几步:

  1. 根据命令行参数创建虚拟机配置

  2. 根据虚拟机配置创建LightMachine对象

  3. 根据虚拟机配置,实例化虚拟机

    1. 具体实例化虚拟机包含的各设备对象

    2. 加载虚拟机内核

    3. 生成设备树

  4. 启动虚拟机的vCPU

  5. 启动虚拟机主线程循环

上面简述了虚拟机创建的5个步骤,下面就关键步骤进行详细分析:

LightMachine对象构建

这里简单介绍一下Rust语言,Rust是一门系统级语言,主要特性源自于C和C++,因此同样可以对内存有很高效的使用。它是强类型的语言,编译器在编译的时候会明确知道数据的具体类型,因此可以就类型的内存操作是否合法做明确的判断。因此其编译的时候提供了严格的安全检查,对于内存使用非法的地方会导致编译失败。从而说它是一门相对安全的系统开发语言。

LightMachine是对轻量级虚拟机对象的类封装。new函数相当于类的构造函数,不过要显示调用。

第一步是打开/dev/kvm的设备描述符。

第二步是创建一个空的虚拟机,kvm.create_vm()。这里实际封装的是ioctl(fd, KVM_CREATE_VM, param)。调用kvm的API接口创建了一个空的虚拟机。该虚拟机当前是没有内存和CPU的。

第三步是创建虚拟机内存。虚拟机内存对象封装在AddressSpace类中。

AddressSpace的数据结构有些复杂,首先其root对象会指向一个Region,初始创建的这个Region是region_container类型,用于管理后面添加的“虚拟内存条”。

第四步是创建guest虚拟机使用的物理内存。调用mmap映射一段内存空间到虚拟机的进程空间。sys_mem.root().add_subregion用于将映射的真实内存region区域添加到上一步创建的AddressSpace对象中,保存在subregions中。

第五步是创建cpu,这里调用vm_fd.create_vcpu来创建vcpu对象。实际底层封装的是ioctl(fd, KVM_CREATE_VCPU)来通知kvm创建vcpu对象。

第六步是创建了一个中断控制设备。这里调用的是gic库创建了一个V3的中断控制器。

第七步是为vcpu设置相应的寄存器。这里根据不同的架构调用vm_fd.get_preferred_target获取kvm返回的kvm_vcpu_init对象。该函数实际封装了ioctl(fd, KVM_ARM_PREFERRED_TARGET)向KVM发送请求获取可以模拟的CPU体系结构。

至此,虚拟机对象基本上已经创建完成,包含虚拟机需要用到的vcpu和memory。

实例化虚拟机

该步骤主要是完成的是1. 设备的实现 2. 内核加载 3. 设备树生成

会遍历该虚拟机配置了哪些设备,然后调用该设备的具体realize函数。当前只是实现了一个mmio设备。

该设备的实现也比较简单,在内核中增加了命令行参数。

加载内核主要实现的就是打开内核img文件,读取镜像文件数据到内存中,并设置bootloader执行的起始位置。

  1. 创建设备树

创建设备主要依赖的是内核C库中设备树创建接口。

启动虚拟机

依次遍历之前创建的vCPU。然后调用CPU::start去启动该CPU。start主要做的就是创建了一个用户空间线程,然后调用cpu.set_task将该线程放到CPU上去执行。线程中包含一个loop,其中cpu.kvm_vcpu_exec处理kvm的返回。如VcpuExit::IoIn,这是经过rust库kvm-ioctls封装过的的退出值。实际在kvm中定义的退出类型有很多。

  1. 总结

在kvm-ioctls中有一个虚拟机的示例,代码在100行以内,实现的主要功能就是类似于StratoVirt当前的功能。StraoVirt所做的是在其上以面向对象的方式封装了大量的类结构,以及总线设备模型,便于之后的设备模块可以在总线上添加。当前的StratoVirt还只是一个具备简单虚拟机功能的代码框架,与qemu之间的差距主要存在于qemu几乎可以模拟所有的主流设备。而StratoVirt当前缺少的就是这部分的代码。

参考

[1] https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/kvm.h

[2] https://docs.rs/kvm-ioctls/0.6.0/kvm_ioctls/

[3] https://www.kernel.org/doc/Documentation/virtual/kvm/api.txt

[4] https://lwn.net/Articles/658511/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK