背景

应用设计需要一个稳定的环境, 而传统的 OS 隔离技术不足以支持这种要求, 比如一个程序消耗了大量的算力并且被 scheduler 赋予了非常高的优先级, 或者系统被程序攻击了, 从而被某个其他进程消耗了很多资源导致当前进程的性能受损, 因此需要更高层的 VM 设计来实现工业界需要的 isolation 级别

同时为了能够承载各种不同来源的软件 (有些软件跑在 linux 上, 有些在 BSD/Windows XP 上), 所以这个虚拟机的设计应当让多种 guest OS 都能以 minimal effort porting 来运行, 也就是不应该强迫所有运行的系统都要提供一致的 app interface

传统的 VM 设计都会带来显著的 Performance Overhead, 但是随着硬件平台的发展, 我们应该尽量设计出一个低 overhead 的 VM 方案

关键词:

  • isolation
  • performance (limited overhead)
  • portability
  • tradeoff btw Heavyweight and Isolation

Intro + Design Ideas

  1. 传统 VMM 的问题
  • 传统 VMM 提供与真实硬件完全相同的抽象(full virtualization), 虽然能支持未修改的操作系统, 但在 x86 架构下效率低, 复杂度高;
  • 例如
    • x86 架构中一些特权指令执行失败时不会自动 trap, 导致难以拦截;
    • 高效虚拟化 MMU 困难;
    • VMware ESX 通过动态二进制翻译和 shadow page tables 来解决, 但代价很大(代码重写, 缓存, 频繁 trap);
  1. full-virtualize 的额外缺陷
  • 某些情况下, guestOS 需要 同时 看到真实与虚拟资源 (如真实时间用于 TCP 超时估算, 真实物理地址用于 superpages 或 page coloring 优化);
  • 完全隐藏真实资源会影响正确性与性能;
  1. Xen 的解决思路: 半虚拟化(paravirtualization)
  • Xen 提供的虚拟机抽象与真实硬件"相似但不完全相同";
  • 需要对客体 OS 做修改, 但 无需修改应用二进制接口 (ABI), 因此应用无需改动;
  • 好处是性能更高, 资源隔离更强;
  1. Xen 的设计原则

  2. 必须支持未修改的应用程序二进制; 也就是当前系统应该支持完全没有修改的 guest OS 生态

  3. 必须支持完整的多应用操作系统, 以便在单个 VM 中运行复杂服务器;

  4. 在 x86 等"难虚拟化"架构上, 高性能和强隔离依赖 paravirtualization;

  5. 即便在 “好虚拟化” 的架构上, 完全屏蔽虚拟化效果也会带来正确性与性能风险;

机制与策略分离

  • 机制(mechanism) = 执行面/数据面: 必须在 hypervisor 内完成, 并且需要强隔离与强一致的动作, 例如:
    • 把 CPU 时间片真正分给哪个域(调度执行)
    • 过滤即将发送的网络包(按已设定的规则逐包检查)
    • 读写磁盘块时做访问控制(检查是否有权限访问这个块)
  • 策略(policy) = 决策面/控制面: 不需要也不应该放在 hypervisor 里, 例如:
    • "CPU 要如何分配? "(比例/权重/上限)
    • "哪些报文类型允许发送? "(ACL, 反欺骗, 限速)
    • "谁能挂载哪个虚拟磁盘? 只读还是可写? "

好处: hypervisor 变小, 可信计算基小(TCB 小), 可维护性与可扩展性强;策略更新在上层软件改就行, 无需动 hypervisor;

简单地说, 就是 Xen 只管 mechanism, 而把 policy 留给上层的管理域(Domain0)去实现

管理结构

  • Xen (hypervisor): 只提供基础控制原语(create/destroy, 设置权重/上限, 授予/回收资源, 建立/删除虚拟设备等)和必需的数据面检查/执行;
  • Domain0 (管理域): 开机创建的特权域, 被授予访问控制接口(control interface)的权限;它运行一个普通的客体 OS(常见是 Linux)+ 一整套管理工具链(管理守护进程/CLI/脚本), 在这里实现"策略逻辑":
    • 如 admission control(是否允许再创建一个域? ), 配额/计费, 服务编排, 报警与自动伸缩, 迁移编排等;
  • 其他域(DomU): 运行业务的普通 VM, 由 Domain0 通过控制接口创建, 配置与监管;

控制接口的功能

  1. domain 生命周期与资源配额
  • 创建/销毁域
  • 设置调度参数(如权重, 上限, 亲和/绑核等)
  • 分配物理内存(以及后续 balloon driver/回收)
  • 授权对物理网卡/磁盘的间接访问权限(通过虚拟设备)
  1. 虚拟网络接口 (VIF) 与虚拟块设备 (VBD)
  • 创建/删除 VIF: 定义这个 domain 的虚拟网卡, 并配置访问控制(例如: 允许的协议/端口, 是否开启源地址 anti-spoofing, 带宽上限/过滤规则等)
  • 创建/删除 VBD: 把后端的物理分区/文件卷暴露成该 domain 可见的"虚拟磁盘", 可设置 只读/读写 等限制
  1. 观测与统计
  • hypervisor 向控制接口提供系统状态与画像(per-domain 的网络/CPU/内存指标, 按包/按流的网络统计等)
  • Domain0 的管理工具据此动态决策 (例如发现拥塞或超配时自动调权, 限速或迁移)

Design Details

控制转移机制

Xen 定义了两种机制:

  1. Hypercalls (同步调用)
  2. Events (异步通知)

Hypercalls (类比系统调用)

  • 是什么: Guest OS 主动调用 Xen 的接口, 类似 应用程序调用系统调用进入内核;
  • 本质: 一次软件 trap, 从较低特权级跳到 Xen(Ring 0);
  • 用途:
    • 用于需要立即处理的 特权 (priviledge) 操作;
      • 例如: Guest OS 想更新页表 \rightarrow 发起 hypercall \rightarrow Xen 验证并应用更新 \rightarrow 返回结果给 Guest OS;
  • 特点:
    • sync: 调用必须等 Xen 处理完成后才能继续执行;
    • 受限接口: 只能调用 Xen 提供的有限操作, 保证安全;

Events (类比中断/信号)

  • 是什么: Xen 异步通知 Guest OS 某个事件发生;
  • 类似于: 中断 (interrupt) \rightarrow 通知设备完成/有新数据
  • Unix 信号 (signal) \rightarrow 通知进程发生特定事件
  • 用途:
    • Guest OS 不需要主动轮询, 而是等事件触发:
    • 网络: 新数据包到达
    • 磁盘: I/O 请求完成
    • 控制: VM 被请求终止

实现机制:

  1. 每个 domain 维护一个 事件 bitmask, 标记待处理的事件;
  2. Xen 在事件发生时更新 bitmask, 然后调用 Guest OS 注册的回调函数 (event-callback handler);
  3. 回调函数负责清除 pending 事件, 并执行相应处理逻辑;

bitmask 指的是每一位对应一种事件类型, 例如:

  • bit0 \rightarrow 网络有数据到达

  • bit1 \rightarrow 磁盘 I/O 完成

  • bit2 \rightarrow domain 被请求终止

  • 延迟处理: Guest OS 可以显式"屏蔽事件"(设置一个 Xen 可读的软件标志位), 类似"关中断", 等准备好时再处理;

  • 好处: 避免在高负载或临界区时被频繁打断;

I/O Rings

  • 在 Xen 架构中, Guest OS 不能直接操作硬件设备, 必须通过 Xen 这个中间层;
  • 这就需要一种高效, 安全的数据传输机制, 让数据能在 Guest OS \leftrightarrow Xen \leftrightarrow 硬件 之间流动;

I/O ring 的结构 (循环队列 + 描述符)

I/O ring 是一个 环形队列 (circular queue), 存放的是 I/O 描述符 (descriptor):

  • 描述符 (descriptor):
    • 不存放实际 I/O 数据, 只是一个指针/引用, 指向 Guest OS 已分配的 buffer;
    • buffer 在 Guest OS 的内存中, Xen 通过描述符找到并操作它;
  • 双向 ring(请求和响应):
    • 请求队列 (request queue):
      • Guest OS 在 ring 中写入请求描述符(比如"读磁盘第 100 块到 buffer A");
      • Xen 取走请求, 执行操作;
    • 响应队列 (response queue):
      • Xen 把结果写入 ring(比如"磁盘第 100 块读完了"), 并返回请求的 ID;
      • Guest OS 读取响应, 确认完成;
  • 指针机制(类似生产者-消费者模型):
    • 请求生产者 (Request Producer): Guest OS 写入请求时更新;
    • 请求消费者 (Request Consumer): Xen 取走请求时更新;
    • 响应生产者 (Response Producer): Xen 写入响应时更新;
    • 响应消费者 (Response Consumer): Guest OS 读到响应时更新;

设计优点:

  1. 异步操作 (Asynchronous operation)
  • Guest OS 发出请求后, 不必等待立即完成, 可以继续执行别的工作;
  • Xen 完成后再通过响应告诉 Guest OS;
  1. 乱序处理(Out-of-order execution)
  • 请求带有唯一 ID;
  • Xen 可以为了性能(比如磁盘调度时做顺序优化)而调整执行顺序, 但最终会通过 ID 匹配响应;
  1. 零拷贝 (Zero-copy)
  • 因为数据直接存放在 Guest OS 的 buffer 里, Xen 不用复制, 只需把硬件 DMA/结果写入那块内存;
  1. 通用性
  • 网络 I/O: Guest OS 先提供 buffer, Xen 在接收到网络包时写入这些 buffer, 并在响应中通知;
  • 磁盘 I/O: Guest OS 提交"读写请求", Xen 调度后把结果写回 buffer 并回应;
  1. 延迟与吞吐的权衡 (latency vs throughput trade-off)
  • Guest OS 可以积累多个请求后, 再一次性 (batch) hypercall 通知 Xen \rightarrow 减少交互次数, 提升吞吐;
  • 同样, Xen 可以延迟事件通知, 等响应累计到一定数量再通知 \rightarrow 避免 Guest OS 被频繁唤醒;

Subsystem Virtualization

CPU Scheduling

  • Xen 使用 Borrowed Virtual Time (BVT) 调度算法;
  • 特点:
    • Work-conserving: 如果有空闲 CPU, 总是会调度可运行的域, 不会浪费资源;
    • 低延迟唤醒 (fast dispatch): 当某个域收到事件(例如网络包), 能快速被调度运行;
      • 这是通过 virtual-time warping 技术实现的: 临时打破"理想公平调度", 优先运行刚被唤醒的域;
    • 好处: 对 TCP 协议很重要, 能及时发 ACK, 不会因为延迟而误判 RTT;
  • 可扩展性: 调度器是通用框架, 其他算法也可以很容易替换或实现;
  • 策略接口: 每个域的调度参数(如权重, 配额)可由 Domain0 的管理软件动态调整;

Time and Timers

  • Xen 提供三种时间概念:
  1. Real time: 自机器启动以来的纳秒数(可与外部时钟源同步);
  2. Virtual time: 域在 CPU 上运行的时间(只在执行时前进, 用于 Guest OS 调度);
  3. Wall-clock time: 实际时钟(real time + offset, 可随时调整而不影响 real time);
  • 每个 Guest OS 可以设置两个闹钟(alarm timer):
  • 一个基于 real time
  • 一个基于 virtual time
  • Guest OS 自己维护内部的定时器队列, 最早的超时由 Xen 的 alarm 来触发;
  • 超时事件通过 event 机制 交付给 Guest OS;

Virtual Address Translation(虚拟地址转换)

  • 问题: x86 使用硬件页表, 难以高效虚拟化;
  • VMware 的做法: 用 shadow page tables, Guest OS 看一个假的页表, hypervisor 同步更新到真实页表;
    • 缺点: 复杂 & 慢(创建新地址空间时开销大, 还要同步 accessed/dirty 位);
  • Xen 的做法:
    • 避免 shadow page table, 直接让 Guest OS 管理真实页表;
    • 限制: Guest OS 只能读, 写操作必须通过 hypercall 交给 Xen 验证;
    • 安全机制:
      • Xen 给每个物理页框分配 类型 (type) 和 引用计数 (ref count):
      • 类型包括 Page Directory (PD), Page Table (PT), LDT, GDT, RW(可写)
      • 页框在同一时间只能属于一种类型
      • 例如: 不能既是 PT 又是 RW
      • 页框分配给页表用途时, 需要一次性验证所有条目 \rightarrow 然后"pin"成 PT/PD 类型
      • 只有当 引用计数=0 且 unpin 时, 页框才能改用途
    • 批量更新优化: Guest OS 可以先在本地缓存页表修改, 再用一个 hypercall 一次性提交, 减少开销;
    • 正确性保证: 通常 Guest OS 会在 切换地址空间前 执行 TLB flush \rightarrow 确保缓存一致;
      • 如果没 flush, 可能会触发缺页异常, Guest OS 的 fault handler 会检查是否有未提交的更新并立即提交;

Physical Memory(物理内存虚拟化)

  • 初始分配: 每个域在创建时就被分配一部分物理内存(reservation);
  • 动态调整:
    • 可以在 reservation 上限内申请更多内存;
    • 也可以主动释放内存回给 Xen;
  • Balloon Driver(气球驱动):
    • XenoLinux 使用 balloon driver 在 OS 内部动态调整内存占用;
    • 通过 OS 自己的内存分配接口"吹大或放气", 而不是改 Linux 内核深处;
    • 进一步扩展: guest OS 的 OOM 机制可以自动触发向 Xen 申请更多内存;
  • 稀疏内存模型 (sparse memory model):
    • Xen 不保证连续物理内存;
    • Guest OS 自己维护一个"伪物理内存"的映射表, 把稀疏的 machine memory 映射为连续的 pseudo-physical memory;
    • Xen 提供 machine\rightarrowphysical 的共享转换表, 保证 guest OS 查表时能拿到正确结果;
  • 优化:
    • Guest OS 在少数情况下会用真实 machine 地址(比如 cache 优化, superpage 分配);
    • 大多数时候, OS 只用 pseudo-physical 地址, 不感知底层稀疏分配;

Network(虚拟网络)

  1. Virtual Firewall-Router (VFR)
  • Xen 把网络抽象为一个 虚拟防火墙路由器 (VFR);
  • 每个域(VM)通过一个或多个 虚拟网卡 (VIF) 接入 VFR;
  • VIF = 现代网卡的简化版:
  • 传输 (Transmit) 队列
    • 接收 (Receive) 队列
    • 每个方向都有一组 规则 (, ), 用于过滤和转发;
  1. 策略配置
  • Domain0 负责安装/删除规则;
  • 常见规则:
    • 防止 IP 源地址欺骗 (spoofing)
    • 根据目的 IP/端口做正确的分流 (demultiplexing)
    • 防火墙规则, 例如禁止某些端口的连接
  1. 发送 (Transmit) 流程
  • Guest OS 把 buffer descriptor 放入 transmit ring;
  • Xen 拷贝描述符, 并拷贝 header (不是整个包);
  • Xen 检查匹配规则, 决定如何处理;
  • payload 不用拷贝 \rightarrow 直接用 scatter-gather DMA 从 buffer 传输;
  • 为了安全, 包所在的页必须 pin 住直到传输完成;
  • Xen 用 简单的 round-robin 在不同 VIF 之间调度, 保证公平;
  1. 接收 (Receive) 流程
  • Guest OS 必须预先提供 页对齐的空 buffer, 放在 receive ring;

  • 当网络包到达:

    • Xen 检查接收规则 \rightarrow 找到目标 VIF;
    • 把这个包直接放入 Guest OS 提供的 buffer(实现零拷贝);
    • 如果没有可用 buffer, 则丢弃数据包;

Disk(虚拟磁盘)

  1. Virtual Block Devices (VBD)
  • 只有 Domain0 能直接访问物理磁盘 (IDE/SCSI);
  • 其他域通过 虚拟块设备 (VBD) 使用存储;
  • VBD 的组成:
    • 一组 extents(磁盘区域)
    • 每个 extent 带有 所有权和访问控制信息
  • VBD 的创建/配置由 Domain0 完成(通过控制接口);
    • 好处: Xen 本身保持简单, 不用像 Exokernel 那样搞复杂的 UDF(用户级设备框架);
  1. 工作流程
  • Guest OS 的磁盘请求通过 I/O ring 传递给 Xen;
  • Guest OS 在提交前可能自己做 请求重排(如优先元数据写, 延迟预读);
  • Xen 接收到请求:
    • 根据 VBD ID + offset 查 翻译表 (translation table), 得到实际物理扇区;
    • 权限 检查(确认该域有权访问该区域);
    • 使用 DMA 在磁盘和 pinned memory pages 之间做 zero-copy 数据传输;
  1. Xen 会做 进一步的调度与批处理 (batching):
  • 从不同域收集请求 \rightarrow round-robin 批处理保证公平;
  • 最终交给硬件层 \rightarrow 由标准的 电梯算法 (elevator scheduler) 优化磁头移动;
  • Guest OS 可以下发 reorder barrier, 告诉 Xen “这些请求必须按顺序执行”(例如写日志);