KVM运行macOS
最近尝试基于Xen运行macOS操作系统,之前已经有人做过类似的研究:
虽然可正常运行,但缺少后续研究,也没有官方支持,所以目前为止Xen只能勉强运行老版本OSX操作系统。运行OSX系统,需要对Xen hypervisor进行修改,如支持MSR 0x35,OSX系统启动时需要据此确定CPU核心数和线程数,但是这个特性连Intel官方开发文档都没有明确说明,所以Xen官方拒绝将此修改合并到Xen主分支代码。
- Xen-devel PATCH x86/hvm: add support for MSR 0x35
- Xen-devel PATCH x86/traps: hypervisor leaf 0x40000010 timing info
自己在本地修改Xen源码,虽然可安装、启动OSX-10.10系统,但还是遇到了其他问题,如外设模拟、系统驱动等,所以系统还是没法正常使用,只好作罢,转而投向更加活跃、有社区支持的OSX-KVM项目,基于KVM运行macOS系统。
准备工作
运行KVM需要CPU支持虚拟化扩展,即Intel VT-x或AMD SVM,如果功能没开启,需要在BISO开启。运行OSX需要KVM和QEMU支持,对KVM和QEMU的修改都已合并到主分支代码,如果系统自带的KVM或QEMU版本太老,OSX是无法正常运行的,至少需要Linux kernel >= 4.7,QEMU >= 2.6。
在The Linux Kernel Archives下载最新稳定版Linux内核编译安装,注意KVM相关虚拟化参数配置。
$ uname -r |
加载KVM内核模块:
$ sudo modprobe kvm_intel |
在Download QEMU下载最新稳定版QEMU编译安装。
$ /usr/local/bin/qemu-system-x86_64 --version |
安装macOS
接着按照OSX-KVM系统安装文档,安装macOS系统。我直接使用的qemu-system-x86_64
,没有借助libvirt
。
$ cat boot-macOS.sh |
安装完,将MacDVD -device及ISO -drive配置注释掉,启动虚拟机。
网络配置
虚拟机可正常运行后,接下来最重要的工作是网络配置,使虚拟机可正常连接网络。
既想让虚拟机可连接外网(但不暴露给外网,外网不能直接访问虚拟机),又不影响主机的网络访问,比较简单的方式是使用TAP interfaces,TAP直接将二层以太帧发送给用户态程序,这正是虚拟网卡(vNIC)期望的工作方式。虚拟机的IP,可通过主机dnsmasq提供的DHCP服务自动获取,然后将虚拟机网络流量通过主机iptables SNAT转发到外网,实现虚拟机访问网络。虚拟机网络连接拓扑:
网桥virbr0创建
创建持久网桥,这样主机重启后就不必重新配置:
$ cat /etc/sysconfig/network-scripts/ifcfg-virbr0 |
iptables SNAT
配置/etc/sysconfig/iptables
添加NAT规则:
-A POSTROUTING -s 172.16.1.0/24 ! -d 172.16.1.0/24 -j MASQUERADE |
配置/etc/sysctl.conf
开启IPv4转发功能:
net.ipv4.ip_forward = 1 |
dnsmasq
配置dnsmasq,给虚拟机提供DHCP和DNS服务。
虚拟机网卡配置
将之前虚拟机启动脚本中的网卡配置,改成:
-netdev tap,id=net100,ifname=tap100,script=/etc/qemu-ifup.sh,downscript=no -device e1000-82545em,netdev=net100,id=net100,mac=00:16:3e:eb:ca:65 |
-netdev tap,id=net101,ifname=tap101,script=/etc/qemu-ifup.sh,downscript=no -device e1000-82545em,netdev=net101,id=net101,mac=00:16:3e:eb:ca:66 |
注意虚拟网卡是e1000-82545em,不是e1000,否则虚拟机网卡无法正常工作。参见QEMU 2.1 Changelog:
More variants of the e1000 NIC are supported (e1000-82540em, e1000-82544gc, e1000-82545em). The default e1000 fails with versions of Mac OS X starting at 10.9, while the new e1000-82545em works with all versions of Mac OS X starting at 10.6.
$ cat /etc/qemu-ifup.sh |
启动虚拟机后,虚拟机就可正常访问网络了。
在使用过程中,发现一个问题,TAP的MAC地址是内核随机分配的,而网桥的MAC地址又是绑定到网桥上所有设备的MAC地址的最小值,这样如果有多台虚拟机同时运行,动态创建关闭虚拟机,会造成网桥MAC地址改变,进而会造成正在运行的虚拟机产生网络丢包,影响网络性能。下面用实验进行详细说明。
- 创建虚拟机前virbr0 MAC地址:
$ ifconfig virbr0 |
- 创建第一台虚拟机,virbr0和tap101 MAC地址:
$ ifconfig virbr0 |
虚拟机网卡:
- 在第一台虚拟机中,进行ping网络测试,同时启动第二台虚拟机。如果第二台虚拟机的TAP MAC地址小于第一台虚拟机TAP MAC地址,网桥virbr0 MAC地址会发生改变,第一台虚拟机中ping网络测试会产生丢包。
tap101 Link encap:Ethernet HWaddr 62:93:B7:8A:03:B7 |
虚拟机需要重新通过ARP探测网桥MAC地址,才能重新恢复正常网络访问。关闭第二台虚拟机,virbr0 MAC地址又会发生改变,再次造成第一台虚拟机网络丢包。
虚拟机内tcpdump抓包,注意看,MAC地址从62:93:B7:8A:03:B7
变成2E:FA:07:80:C6:23
。
一种解决方案是,将所有虚拟机的TAP MAC地址配置成同一个值,这样网桥MAC地址不会发生改变,也不影响虚拟机网络访问。修改/etc/qemu-ifup.sh:
$ cat /etc/qemu-ifup.sh |
参考:
- QEMU User Documentation
- QEMU Configuring Guest Networking
- How does the libvirt deal with the vnet mac address
- Linux bridge: MAC addresses and dynamic ports
- Tap Interfaces and Linux Bridge
- Linux Bridge - how it works
- Wikipedia TUN/TAP
- Linux kernel TUN/TAP device driver
- How to configure a Linux bridge interface