After my previous attempt the other day to create a nested-guest(kvm on kvm) with Intel arch, I got hold of an AMD server machine with virt-extensions enabled and gave it a whirl. This went slightly smoother than the Intel attempt.
Some config info about the physical host, regular-guest and nested-guest. (All of them are Fedora-16; x86_64)
- Physical Host (Host hypervisor/Bare metal)
-
[root@phy-host-amd]# virsh nodeinfo CPU model: x86_64 CPU(s): 16 CPU frequency: 2000 MHz CPU socket(s): 2 Core(s) per socket: 8 Thread(s) per core: 1 NUMA cell(s): 1 Memory size: 8173352 kB
- Regualr Guest (Or Guest Hypervisor)
- Config: 4GB Memory; 6 vcpus; 22GB Raw disk image w/ cache=’none’ enabled in the libvirt xml
- Nested Guest
- Config: 2GB Memory; 3 vcpus; 10G Raw disk image
Ensure nesting is enabled on the physical host
Let’s ensure kvm_amd kernel module is enabled with ‘nested’ virt.
[root@phy-host-amd ~]# modinfo kvm_amd | grep -i nested parm: nested:int [root@phy-host-amd ~]# [root@phy-host-amd ~]# cat /sys/module/kvm_amd/parameters/nested 1 [root@phy-host-amd ~]# [root@phy-host-amd ~]# systool -m kvm_amd -v | grep -i nested nested = "1" [root@phy-host-amd ~]#
CAVEAT: To make life a little easier, I configured bridged networking on the physical host to ensure our regular-guest gets a bridged IP; and later, nested-guest gets a NATed IP. I’m noting it here because, the physical host initially had no bridging. The default libvirt bridge virbr0 has 192.168.122.0/24 IP space. So once we set up the regular-guest(or guest-hypervisor), we’ll end up having the same IP space. I tried to fix this prob. by creating another ‘persistent’ libvirt network interface and enabled autostart of it. [virsh net-add; virsh net-define; virsh net-autostart ]. But, it wasn’t elegant and messed up networks on reboot.
Set up the guest hypervisor
Create a minimal regular-guest using virt-install . The one I used is posted here
Now, add the cpu attribute to the regular-guest’s libvirt xml to expose AMD’s svm instructions, which comes with Opteron_G3 model .
Edit the xml using virsh:
# virsh edit regualr-guest
(which will also define the xml)
Here is the attribute to be added to the guest hypervisor’s libvirt xml:
<cpu> <arch>x86_64</arch> <model>Opteron_G3</model> <vendor>AMD</vendor> <topology sockets='2' cores='8' threads='1'/> <feature name='wdt'/> <feature name='skinit'/> <feature name='osvw'/> <feature name='3dnowprefetch'/> <feature name='cr8legacy'/> <feature name='extapic'/> <feature name='cmp_legacy'/> <feature name='3dnow'/> <feature name='3dnowext'/> <feature name='pdpe1gb'/> <feature name='fxsr_opt'/> <feature name='mmxext'/> <feature name='ht'/> <feature name='vme'/> </cpu>
And, restarted the regular-guest, so that it boots w/ the -cpuflag which the AMD virt extensions:
[root@phy-host-amd ~]# ps -ef | grep -i qemu-kvm qemu 26677 1 14 10:39 ? 00:00:30 /usr/bin/qemu-kvm -S -M pc-0.14 -cpu phenom,+wdt,+skinit,+osvw,+3dnowprefetch,+misalignsse,+sse4a,+abm,+cr8legacy,+extapic,+cmp_legacy,+lahf_lm,+rdtscp,+pdpe1gb,+popcnt,+cx16,+ht,+vme -enable-kvm -m 4096 -smp 6,sockets=2,cores=8,threads=1 -name regular-guest -uuid 8f6a4478-496b-51d8-2de2-ff7fdb964af3 -nographic -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/regular-guest.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -drive file=/var/lib/libvirt/images/regular-guest.img,if=none,id=drive-virtio-disk0,format=raw,cache=none -device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -netdev tap,fd=24,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:5f:c6:5f,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -usb -device usb-tablet,id=input0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
Now, let’s fetch the IP of the regular-guest using virt-cat
[root@phy-host-amd ~]# virsh list Id Name State ---------------------------------- 5 regular-guest running [root@phy-host-amd ~]# [root@phy-host-amd ~]# virt-cat regular-guest /var/log/messages | grep 'dhclient.*bound to' Jan 17 10:13:06 dhcpyy-zz dhclient[732]: bound to ww.xx.yy.zz -- renewal in 32578 seconds.
(Note: ‘ww.xx.yy.zz’ above will be a bridged IP address)
Create the nested guest
Now. install virt-packages in the regular-guest. Also, let’s check if the /dev/kvm char device is exposed in the regular-guest ; and start the libvirtd service.
[root@regular-guest ~]# file /dev/kvm /dev/kvm: character special [root@regular-guest ~]# systemctl status libvirtd.service libvirtd.service - LSB: daemon for libvirt virtualization API Loaded: loaded (/etc/rc.d/init.d/libvirtd) Active: active (running) since Tue, 17 Jan 2012 10:49:25 -0500; 5s ago Process: 1440 ExecStart=/etc/rc.d/init.d/libvirtd start (code=exited, status=0/SUCCESS) Main PID: 1448 (libvirtd) CGroup: name=systemd:/system/libvirtd.service ├ 1448 libvirtd --daemon └ 1501 /usr/sbin/dnsmasq --strict-order --bind-interfaces --pid-file=/var/run/libvirt/network/default.pid --conf-file= --exce...
Proceed with installing a minimal F16 nested-guest w/ virt-install. The script I used is here
Debugging note: Once the guest install is finished, fix the serial console access by disabling plymouth-service using this workaround. This will let us login via virsh serial console(to get kernel and boot messages) w/o any line breaks while entering credentials:
# ln -s /dev/null /etc/systemd/system/plymouth-start.service
Get the (NATed) IP of the nested-guest. (Also, grepped for the qemu-kvm command-line of the nested-guest.)
[root@regular-guest ~]# virsh list Id Name State ---------------------------------- 2 nested-guest running [root@regular-guest ~]# ps -ef | grep qemu-kvm qemu 2245 1 2 Jan17 ? 00:20:11 /usr/bin/qemu-kvm -S -M pc-0.14 -enable-kvm -m 2048 -smp 3,sockets=3,cores=1,threads=1 -name nested-guest -uuid 2aae2ab5-ddb6-2585-aa16-7fe97296f34b -nographic -nodefconfig -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/nested-guest.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -drive file=/var/lib/libvirt/images/nested-guest.img,if=none,id=drive-virtio-disk0,format=raw -device virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 -netdev tap,fd=24,id=hostnet0 -device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:0e:4e:53,bus=pci.0,addr=0x3 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,id=serial0 -usb -device usb-tablet,id=input0 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 [root@regular-guest ~]# virt-cat nested-guest /var/log/messages | grep 'dhclient.*bound to' Jan 17 11:08:30 localhost dhclient[721]: bound to 192.168.122.220 -- renewal in 1393 seconds. [root@regular-guest ~]#
SSh into the nested-guest, install virt-what package and run to see if we’re on a hypervisor
[root@localhost ~]# cat /etc/fedora-release Fedora release 16 (Verne) [root@localhost ~]# ifconfig eth0 | grep inet inet addr:192.168.122.220 Bcast:192.168.122.255 Mask:255.255.255.0 inet6 addr: fe80::5054:ff:fe0e:4e53/64 Scope:Link [root@localhost ~]# [root@localhost ~]# virt-what kvm
Wooo!! so we’re on an OS which is inside an OS which is inside an OS.