啥几种类型的VMM之类的东西就不用说了,OS课本上多的是老掉牙的图。主要要说的是以下几个东西。
para-virtualization:半虚拟化就是guest OS要进行修改,才能跑上去。例如Xen(详见论文)就是把guest OS给改改,改guest OS,让它不做特权操作,只通过hyperCall来和host OS通信。这样子可以跑在不支持虚拟化扩展的老x86硬件上,同时也没有复杂的设备模拟,性能也高。 full-virtualization:全虚拟化就是guest OS不经过修改,就可以直接跑上去。典型的就是KVM还有VMware。全虚拟化要想性能好,一般需要处理器的虚拟化支持。
Xen论文:Xen and the Art of Virtualization
KVM论文:kvm: the Linux Virtual Machine Monitor
x86的虚拟化扩展主要包括了如下三方面:
我们可以看看这三方面各自解决了什么问题:
这三点在理解的时候可以对比OS与process的关系。OS是process的运行时,VMM是OS的运行时。OS给process虚拟化了各种资源,同样的,VMM也给OS虚拟化了各种资源。
第一个是引入了一个guest OS模式。传统的x86不太好虚拟化,主要就是因为它的指令行为设计得不好,会有silent fail以及side effect之类的(不知道具体是不是这个说法,反正x86指令集就是虚拟化不太友好),不太好拿trap and emulate的方式来做虚拟化。现在引入了这个mode后,在这个模式下,指令的行为可以被trap and emulate。值得注意的是guest mode与x86传统的ring权限结构是正交的。guest OS运行时是在guest mode,ring 0,guest OS的app是运行在ring 3。只要它们做了特定的非法动作或者机器上来了某些中断,就会触发VMExit。host OS、host OS上的程序,VMM运行在root mode,host OS是ring 0,kvm.ko也是ring 0,qumu是ring 3。在root mode,处理器的行为就和传统的处理器一样。在root mode下,通过VMEntry之类的指令可以再进入guest mode。
下一个就是hardware state switch,guest OS的hardware context可以被保存,修改再恢复。这个可以对比OS与process的关系,OS要能保存、修改再恢复process的hardware context。VMM就需要有能力保存、修改、再回复OS的hardware context。VMM的这个hardware context在Intel上面叫vmstruct。
最后就是exit reason reporting。这个就类似process trap时的error code。有了这个,VMM就可以做针对性的处理。
KVM是Linux是给linux kernel增加了一个子系统,添加了这个子系统后,linux kernel就可以变成一个hypervisor了。同时,kvm还用到了qemu来进行设备模拟,把它放在用户态。
由于虚拟化本质上还是靠trap and emulate来实现。不同的是,如果硬件上支持更多的虚拟化扩展,可以把guest OS的更多代码直接在硬件上运行,可以尽量少地触发trap,提升性能。
大致流程是:KVM guest OS运行在VMX non root mode下,在这个下面,它可以自由地干自己想干的事情,例如进程调度,内存分配,巴拉巴拉。然后等到实在干不了的时候,例如IO,fault之类的,就会VMExit,VMExit后,可以由KVM的内核部分来处理CPU,memory相关的,也可以有host kernel再把任务丢到user space,由qemu进行设备模拟。
VMM本质上就是许多个事件处理循环,这里本质上就是在讲和VMM,host OS,guest OS相关的一些事件处理循环。
KVM在linux传统的kernel mode和app mode之外增加了一个guest mode。它们之间的转换可以看下图。 这张图主要讲的是VMM,host OS,guest OS之间是怎么切来切去的。 首先kvm分为用户态和内核态的部分。用户态的部分主要包括qemu的设备模拟以及一些工具,我们把用户态的部分称为kvm.user,内核态的部分主要是kvm.ko。
然后这篇文章的剩下部分基本都是在介绍CPU,MMU以及IO这几大子系统是如何实现虚拟化的。 总的来说,KVM的核心设计思路就是把不得不由内核干的事情,通过内核的kvm子系统来完成,然后其他部分,包括虚拟化CPU,IO,MMU全部由user process来干。
学习地址: Dpdk/网络协议栈/vpp/OvS/DDos/NFV/虚拟化/高性能专家-学习视频教程-腾讯课堂
更多DPDK相关学习资料有需要的可以自行报名学习,免费订阅,久学习,或点击这里加qun免费
领取,关注我持续更新哦! !
那么KVM具体是如何实现的呢?一个guest OS在host OS看来到底是什么?进程调度,切换,内存分配,IO都是怎么搞的呢? 要知道这些,就要知道KVM的具体实现了。
一个KVM虚拟机就是一个运行qemu-kvm的进程,一个vcpu就是进程里面的一个线程。这个虚拟机进程里面除了有N个VCPU线程,还会有其他的IO、管理线程等等。
KVM guest OS根本不用管它的那个vcpu在host os里面是不是被抢占了,是不是跑得快,跑得慢了,它只负责把它的任务调度到VCPU上面运行,然后这些VCPU线程就像普通的Linux线程一样,被host调度。所以这个里面其实有两级的调度。
host OS根本不管你这个线程上面运行的是guest OS kernel还是guest OS的app还是VMM的部分代码,host OS统统不关心,它只管调度运行它就是了。
问题1:host os怎么知道guest OS的vcpu上面有任务呢? host OS不用知道guest OS的vcpu上面是不是有任务,只要guest OS没有halt它的vcpu,那么这个vcpu的thread就是runnable的,那么host os就会调度运行这个线程。
问题2:guest OS里面的idle进程始终在运行,怎么避免它们消耗过多的host CPU呢? idle在实现时一般是通过特殊指令halt CPU,假如guest OS进入了idle,halt了VCPU,那么对应的,它的VCPU线程就不是runnable了,那么host OS就不会调度这个VCPU线程,那么就不会消耗host cpu了。
guest OS的内存其实是来自qemu-kvm的虚拟内存空间。所以这里又是一个两级的映射,KVM最一开始是用shadow page的方式来搞,性能不太好。后来硬件支持nested paging后,就好搞多了。
KVM CPU以及memory管理一般是由内核KVM模块完成的。
KVM IO可以比较简单,例如guest OS要IO,对虚拟的设备进行IO,触发了中断,然后CPU退出到host kernel。然后host kernel,可以把这个请求丢给qemu,qemu一般是一个IO线程,它在用户态做好IO模拟后,再切回到guest OS里面去,让它接着运行。
使用qemu进行设备的完整模拟,性能非常差,现在在KVM中,一般是使用virtio这类半虚拟化设备。