海光 CPU Windows libvirt 虚机蓝屏问题
May 3, 2024 13:00 · 951 words · 2 minute read
一句话描述现象:基于 KubeVirt 底座的 Windows 虚拟机在海光处理器物理节点上启动后蓝屏。
和 OpenStack 一样,KubeVirt 虚机本质上也是 libvirt - qemu - kvm 的模式。
真实原因
某些操作系统并不支持海光(Hygon)CPU:Windows 在读取到 CPU 供应商为海光后,会直接蓝屏。并不是完全不能跑,而是开发商(微软)不可能针对市面上所有的 CPU 开发与测试其操作系统,只会支持主流的处理器厂家的主流 CPU;为了避免用户在海光之类非主流国产厂商的处理器上使用 Windows 时可能遇到一些奇怪的问题,就采取了一刀切的方式。
Linux 上查看 CPU 详细信息的方式:
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 128
On-line CPU(s) list: 0-127
Thread(s) per core: 2
Core(s) per socket: 32
Socket(s): 2
NUMA node(s): 1
Vendor ID: HygonGenuine
BIOS Vendor ID: Chengdu Hygon
CPU family: 24
Model: 1
Model name: Hygon C86 7285 32-core Processor
BIOS Model name: Hygon C86 7285 32-core Processor
Vendor ID
一行表明 CPU 供应商为海光(Hygon),我们对比看一下英特尔的 CPU:
$ lscpu | grep "Vendor ID"
Vendor ID: GenuineIntel
BIOS Vendor ID: Intel(R) Corporation
如果不做处理,libvirt 在启动 qemu-kvm 时会直接使用宿主机的 CPU Vendor ID,即虚机内外保持一致:上述情景即是。
这点也可以在 qemu 的源码中证实:
https://gitlab.com/qemu-project/qemu/-/blob/v7.2.0/target/i386/cpu.c#L5097-5109
static void x86_cpu_load_model(X86CPU *cpu, X86CPUModel *model)
{
/* sysenter isn't supported in compatibility mode on AMD,
* syscall isn't supported in compatibility mode on Intel.
* Normally we advertise the actual CPU vendor, but you can
* override this using the 'vendor' property if you want to use
* KVM's sysenter/syscall emulation in compatibility mode and
* when doing cross vendor migration
*/
/*
* vendor property is set here but then overloaded with the
* host cpu vendor for KVM and HVF.
*/
object_property_set_str(OBJECT(cpu), "vendor", def->vendor, &error_abort);
}
解决方案
因为海光 CPU 采用的是 AMD EPYC 架构,所以我们在 libvirt domain 中修改供应商,将其伪装成 AMD EPYC 处理器:
<cpu mode='custom' match='exact' check='none'>
<model fallback='forbid' vendor_id='AuthenticAMD'>EPYC</model>
</cpu>
需要修改 KubeVirt Domain API 中的 CPU 字段定义实现:
type CPUModel struct {
Fallback string `xml:"fallback,attr,omitempty"`
VendorID string `xml:"vendor_id,attr,omitempty"`
Value string `xml:",chardata"`
}
type CPU struct {
Check string `xml:"check,attr,omitempty"`
Mode string `xml:"mode,attr,omitempty"`
Model *CPUModel `xml:"model,omitempty"`
Features []CPUFeature `xml:"feature"`
Topology *CPUTopology `xml:"topology"`
NUMA *NUMA `xml:"numa,omitempty"`
}
修改 virt-launcher 中的 converter,识别宿主机 CPU 供应商 ID:如果宿主机处理器为海光(Hygon),就将其伪装成 AMD EPYC。
OpenStack 或其他基于 libvirt 的 IaaS 系统中相同问题的处理方法也类似,可参考 https://hlyani.github.io/notes/openstack/openstack_hygon_patch.html。
经过验证 Windows 虚机可成功启动,libvirt 启动 qemu 时带上了参数 -cpu EPYC,vendor=AuthenticAMD
:
$ ps -ef | grep qemu-kvm
/usr/libexec/qemu-kvm -name guest=mec-ba3abbb298f043fabaa0014644433b30_i-0778195e61b44584ab13,debug-threads=on -S -object {"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/run/kubevirt-private/libvirt/qemu/lib/domain-1-mec-ba3abbb298f043fa/master-key.aes"} -machine pc-q35-rhel9.2.0,usb=off,dump-guest-core=off -accel kvm -cpu EPYC,vendor=AuthenticAMD,monitor=off
在虚拟中查看硬件也显示为 AMD EPYC 处理器。
需要注意
如果物理机集群的计算节点中还存在其他供应商的服务器,那虚机热迁会有问题(从英特尔节点热迁至海光节点或从海光热迁至英特尔),需要额外考虑热迁时的调度;如果计算节点均为海光处理器,就没有问题。