xen结构概述
一个 Xen 虚拟化环境包括一组项目,它们一起工作来提供虚拟化环境:
Xen hypervisor;
dom0;
domain management and control,域的管理和控制;
domU PV 客户机;
domU HVM 客户机。
它们之间的关系参见:
http://www.chenyajun.com/2009/03/01/xen-virtualization-model-explored/
hypervisor 是操作系统以下硬件以上的一个软件抽象。负责 CPU 调度,虚拟机内存分配。hypervisor 不仅为虚拟机抽象硬件,也要控制虚拟机的执行。它对于网络、存储设备和其它 IO 功能等一无所知。
dom0
是一个修改的 linux 内核,是一个运行在 xen hypervisor 之上的独特虚拟机,对访问物理 IO 和其它 domu 虚拟机具有特殊的权利。 xen 虚拟环境需要 dom0 在其它任何虚拟机之前先启动。
在 dom0 中包括的驱动用来支持 domu 的网络和本地磁盘请求,包括Network Backend Driver 和 the Block Backend Driver。
domU
所有运行在 Xen hypervisor 上的半虚拟化客户机被称为 domain U PV 客户机,可以运行修改过的Linux,Solaris,FreeBSD 和其它操作系统。所有运行在 Xen hypervisor 之上的完全虚拟化的客户机被称为 Domain U HVM 客户机,运行标准的 windows 或者其它未修改的操作系统。
DomU PV 客户机意识到它不直接访问到硬件,认识到其它的虚拟机运行在同样的机器上。DomU HVM Guest 不会意识到它在和其它虚拟机共享硬件资源。
一个 domU PV 客户机包含用于网络和磁盘访问的 2 种驱动,PV Network Driver 和 PV Block Driver。
一个 domU HVM 客户机没有那种 PV 驱动;取而代之的是在 dom0 下对每个 HVM 有一个特别的守护进程:qemu-dm。它支持 domU HVM 客户机来进行网络和磁盘访问请求。
domU HVM 客户机必须进行一些初始化,加载一些软件模块(固件)来模拟 BIOS 。
dom 的管理和控制
一系列的 Linux 进程被归类为 dom 管理和控制工具,它们被用来进行 dom 0 内虚拟机的管理和控制。
xend
Xend 是一个 python 应用,它是 Xen 环境的系统管理器。它调节 libxenctrl 来向 hypervisor 请求,所有经由 Xend 的请求通过 xm 工具用 xml-rpc 接口发起。
xm
命令行工具,接收用户输入通过 xml rpc 传递到 Xend。
Xenstored
这个维护在 dom0 和 domU 之间的内存和事件通道等的信息。
libxenctrl
一个 C 库提供 Xend 和 Xen hypervisor 通过 dom0 对话的能力。在 dom0 中,privcmd 分发请求到 hypervisor。
Qemu-dm
每个 HVM 客户机要求有自己的 Qemu 守护进程。这个工具处理所有来自 domU HVM 完全虚拟化的客户机的网络和磁盘请求。Qemu 必须存在于 Xen hypervisor 之外,因为它必须能访问 dom0 中的网络和IO。
Xen 虚拟固件
一个虚拟的 BIOS 插入到每个 domU HVM 客户机中,保证操作系统接收到在正常启动过程中各种标准的启动指令。
dom0 和 domU 之间的通讯
Xen hypervisor 不用来支持网络或者磁盘请求,因此一个 domU 通过 hypervisor 向 dom0 通信来进行磁盘或者网络请求。
domU PV 客户机块设备驱动接收到磁盘写请求时,它将通过 Xen hypervisor 写数据到和 dom0 共享的一块本地内存。在 dom0 和 domU PV 客户机之间存在一个事件通道允许它们使用 Xen hypervisor 的异步域间中断来通信。dom0 将接收到一个来自 hypervisor 的中断引起 PV Block Backend Driver 来访问本地系统内存读取 domU PV 客户机共享内存中的块。共享内存中的数据然后被写到本地磁盘。
The Role of dom0
原文来自 The definitive guide to hypervisor。
一本讲 xen 原理的书,非常难得。
翻译一些 xen 概念备查。
dom0 的角色
hypervisor 的目的是允许客户机运行。Xen 在被称为域的环境中运行客户机,它封装了一个完全的运行虚拟化的环境。当 Xen 启动时,第一件要做的事便是加载一个 dom0 的客户机内核。这典型的做法是在bootloader 中以一个核的方式来指定,可以在不修改文件系统驱动的情况下加载。dom0 是第一个被加载的客户机,具有高的权限,相比之下,其它的域被称为 domU。U 是指 unprivileged。
dom0 对 xen 是非常重要的。Xen 并不包括任何设备驱动,也不是一个用户接口。它们由操作系统和 dom0 中的用户工具提供,dom0 客户机一般是 Linux,在将来可能添加对NetBSD 和 Solaris 的支持。
dom0 最明显的人物是处理设备。dom0 客户机可以运行在一个比其它客户机较高的特权级别而可以访问硬件。因此 dom0 需要在安全上被加固。
处理设备的部分功能便是对虚拟机进行各种请求的转接。由于很多硬件不被多种客户机操作系统本地支持,因此有必要为客户机提供它自己可用的虚拟设备。
下图显示了一个包被一个 domU 中的客户机发送时会发生什么。首先,它将穿过通常的 TCP/IP 协议栈。栈底不是一个通常的网络接口驱动。它是将包放到一片共享内存的代码,这个内存段已经在事先使用 Xen 授权表和 Xenstore 所共享。
硬件设备分离的另外一部分,运行在 dom0 中,将包从缓冲中读入,插入到操作系统的防火墙组件中,通常是一些类似 iptables 之类的东西,然后包将被认为是来自真实的网络接口那样被路由。一旦包通过了任何相关的防火墙规则,将被像通常数据包那样被送达到真实的设备驱动。
网络设备分离同样和网卡无关。Xen 对这些设备提供了一个简单的接口,使得迁移系统到 Xen 容易实现,对任何驱动有 3 种组件:
分离驱动(The split driver);
转接器(The multiplexer);
真实的驱动(The real driver)。
分离驱动通常被设计为将 domU 中的数据移动到 dom0 中,它使用了共享内存中的ring buffer 来完成。
真实的驱动应该已经存在于 dom0 操作系统中,因此它不应该是 Xen 的一部分。
dom0 还要负责处理管理任务。当 Xen 创建一个新的 domU 客户端时,它要这样响应来自 dom0 的 hypercall。这通常是通过 python 脚本完成,它处理相关的客户端创建策略并发布相应的 hypercall。
dom0 提供了这些接口给 hypervisor。xend 和 Xenstored 提供了重要的特性。其中一个提供管理接口,另外一个提供后端存储(back-end storage)给 Xenstore。
一个非特权域 domU 受到的限制很多,它一般不允许直接使用 hypercall 访问硬件。取而代之的是 fomU 客户机一般实现了某些分离驱动的前端(front end of some split drivers).
在一个单一的机器上,你可以有任意数量的 domU,它们还能迁移。是否可以迁移取决于配置;如何客户机的配置紧密和硬件耦合而不好迁移。一个使用类似 NFS 或者 iSCSI 的可以实时迁移,一个使用块设备驱动的可以挂起到闪存设备后迁移到另一个不同的机器上,只要它没有使用不被迁移支持的硬件。
关于 HVM 域
现代的 x86 的架构使得可以扩展 Xen 支持未经修改的客户端。在 xen 3.x 系列之前只支持半虚拟化。更新的版本允许运行 Hardware Virtual Machine (HVM) 客户端。
一个未经修改的 OS 不支持 Xen 的分离硬件驱动。这意味着 Xen 必须模拟一些东西使得客户端可以支持。一小部分设备可以这么做,使用qemu。
HVM 客户机和半虚拟化的客户机有几个不同点,在启动时,一个半虚拟化客户机以保护模式启动,某些包含启动信息的内存页由 hypervisor 映射,但是一个 HVM 客户机从实模式启动,从一个模拟的 BIOS 获得配置信息。
如果一个 HVM 客户机要使用 xen 特定特性的优点,它需要使用 cpuid 指令来访问一个虚拟机特定的寄存器并访问 hypercall 页。然后可以和半虚拟化的客户机类似那样通过调用在 hypercall 页中一个偏移来发布 hypercall,然后使用比如 vmcall 指令来转移到 hypercall。
Xen 配置
一个实际的 xen 配置至少包含一个 domU 客户机。在下左的例子中,所有的硬件都由 dom0 主机所控制。这不总是理想的。如果一个驱动包含bug,它会导致整个 dom0 崩溃,然后导致整个客户机当机。因此,隔离一个驱动在一个特定的域中是有益的,这个域只是导出了上面谈到的分离驱动(右边)。在支持 IOMMU 的平台上可以完全阻止有问题的驱动干扰其它客户机。
Xen 事件模型
下表显示了 Xen 中对应的 UNIX 接口。事件直接来自 Xen,可能代表硬件或者虚拟的中断,或者可能由其它的客户端发出。和 UNIX 信号一样,它们可以被用来构建更加复杂的异步的通信路径,比如通过分配一事件通道来指示一个共享内存的内容是否更新。和信号一样,Xen 事件通过回调函数分发。
Xen 事件和 UNIX 信号分享了很多硬件中断,但是它们只是 Mach Ports 在概念上的亲戚。Xen 事件通过通道分发,你不能从一个任意的发送者获取任意的事件。当一个进程要发送信号给一个进城时,它必须首先知道远程进程的 ID,然后使用 kill 系统调用。类似的在 Xen 中客户机发送一个异步的事件到另外一个域。这要求下面的步骤:
1、接收端创建一个新的未绑定的端口;
2、接收端通告端口的存在(通常通过 Xenstore)。
3、发送端创建一个新的端口。
4、发送端发送事件。
在 UNIX 系统上,一个进程可以给另一个进程发送 SIGSEGV 信号使得另一个进程当掉。在 Xen 中不行的,因为域的隔离对于安全是很重要的。这个机制保证一个客户端只接收它知道如何处理的事件。
使用共享内存进行通信
UNIX 信号模型传递事件很快,但是可能不足以构建一个通用目的的 IPC 机制。Xen 只是一个最小的 hypervisor,它没有实现其它几种 IPC 机制,比如管道、消息队列,但是共享内存除外。
Xen 中的网络设置
如前所描述,后端驱动(backend driver)运行在特权域,前端驱动(frontend driver)运行在非特权域。非特权的客户端发出设备请求到前端驱动。前端驱动然后和运行在特权域中的后端驱动通信。特权域将请求排队向实际物理硬件请求。
前端和后端驱动的通信通过使用 XenBus 的系统内存来完成,这是一个用来共享事件通道和生产者/消费者的环缓冲。为了避免昂贵的数据拷贝,XenBus 通过简单映射来完成。比如当要写数据到磁盘或者通过网络发送数据,一个属于非特权域的缓存可能被映射到特权域。同样,要从磁盘读数据或者接收来自网络的数据,一个由特权域控制的缓存可以被映射到非特权域。
这种通信通过 XenStore 来建立。当前端驱动启动时,它使用 XenStore 来建立一个共享内存池和与后端驱动通信的事件通道。在连接建立以后,前端和后端将请求或者响应放置到共享内存中通过事件通道向彼此发送通知。XenStore 向后端和前端驱动提供了对这种连接的可见性。
桥接、路由和 NAT
Xen 提供了 3 种虚拟网络模型来供客户机访问物理设备——桥接、路由和 NAT。在桥接模式中,虚拟网络接口(vif)在外部局域网是可见的,在路由模型中,vif 在外部局域网是不可见的,但是 IP 是可见的。在 NAT 模型中,vif 在外部局域网不可见,它也没有一个外部可见的 IP 地址。
在桥接模式下, brctl 工具被用来创建软件方式的桥接接口,一个物理网络接口然后附加到桥上。Xen 客户机域的后端 vif 能被附加到这个桥上。当桥接口接收到来自物理接口的包时,物理网络接口将依据各域的虚拟网卡的 MAC 地址转发它们到不同的域上。
在路由模型下将使用 iptables 机制来进行路由。由物理接口所收到的所有的包将被驱动域的网络 IP 层所处理。驱动域(dom0)查找路由表条目并将包转发到不同的客户机 IP 地址。在路由模式下,驱动域连接 2 个不同的网段:内部由客户机使用的网段和连接外部网络的网段。
在驱动域作为一个 NAT 网关时,驱动域仍然作为一个路由器,但是更进一步映射一个它自己的 IP 地址和端口到一个客户机的 IP 地址和端口。客户机的 IP 地址隐藏在驱动域后面对外部网络不可见。
Linux 防火墙提供了 iptables ,而 bridge-utils 则提供了 etables 来进行基本的 MAC 地址过滤。也可以指定一个物理网卡给一个域使用。
veth0、vif0.0 是 dom0 的网络接口。veth0 被重命名为 eth0。xenbr0 接口是软桥接接口。vif1.0 是运行的客户机的后端网络接口。
peth0、xenbr0、vif0.0、vif1.0 都共享同样的 MAC 地址 FE:FF:FF:FF:FF:FF,它是以太网的广播地址。这意味着实际的网络接口、dom0 的回环接口、客户机的后端接口都向 xenbr0 广播。当物理网卡接收到包时,它直接发送到桥接接口 xenbr0,这个桥接接口通过包的 MAC 地址决定将包转发到哪个域的后端接口。因此 peth0 不需要 IP,只需要 MAC 地址。物理接口的原先 IP 已经被告知给 eth0——驱动域的虚拟前端接口。xenbr0 通过 MAC 地址是 00:11:25:F6:15:22 或者是 00:16:3e:45:e7:12 来决定包转发到 eth0 或者 vif1.0。客户域相应的前端接口被命名为 eth0。从 dom0 的角度看,客户机中 eth0 实际是 vif1.0。
brctl 命令的显示:
[user@Dom0]# brctl show bridge name bridge id STP enabled interfaces xenbr0 8000.feffffffffff no vif1.0 peth0 vif0.0