support/testing: test_xen: repair and leverage xen tools

Current test runs a Xen hypervisor and a Linux dom0, from which we can
detect that we run under Xen but not much more. Indeed, with current
test's setup the Xen tools are not functional.

We add back networking to our stripped-down kernel config to repair Xen
tools.

With Xen tools functionals, we can enhance the test with the creation of
a VM. To be able to use the rootfs that we build in both the dom0 and in
this new dom1, we switch to an initramfs; no more rootfs partition in
the image. After stripping the ramdisk a bit we can even reduce Qemu's
memory to 1 GB.

Suggested-by: Julien Olivain <ju.o@free.fr>
Signed-off-by: Vincent Stehlé <vincent.stehle@laposte.net>
Signed-off-by: Julien Olivain <ju.o@free.fr>
This commit is contained in:
Vincent Stehlé
2025-01-27 23:03:26 +01:00
committed by Julien Olivain
parent 3bfa5ebcbf
commit cd0ffd598c
7 changed files with 138 additions and 15 deletions

View File

@@ -1,15 +1,20 @@
import os
import pexpect
import infra.basetest
class TestXen(infra.basetest.BRTest):
# We have a custom kernel config to reduce build time.
# Our genimage.cfg is inspired from qemu_aarch64_ebbr_defconfig as we boot
# Xen with UEFI.
# Xen with UEFI. We run only in the initramfs; this allows to use a single
# ramdisk image for both the host and the guest.
# The Xen startup scripts need bash.
config = \
"""
BR2_aarch64=y
BR2_TOOLCHAIN_EXTERNAL=y
BR2_ROOTFS_OVERLAY="support/testing/tests/package/test_xen/overlay"
BR2_ROOTFS_POST_BUILD_SCRIPT="support/testing/tests/package/test_xen/post-build.sh"
BR2_ROOTFS_POST_IMAGE_SCRIPT="support/testing/tests/package/test_xen/post-image.sh support/scripts/genimage.sh"
BR2_ROOTFS_POST_SCRIPT_ARGS="-c support/testing/tests/package/test_xen/genimage.cfg"
BR2_LINUX_KERNEL=y
@@ -21,9 +26,7 @@ class TestXen(infra.basetest.BRTest):
BR2_PACKAGE_XEN=y
BR2_PACKAGE_XEN_HYPERVISOR=y
BR2_PACKAGE_XEN_TOOLS=y
BR2_TARGET_ROOTFS_EXT2=y
BR2_TARGET_ROOTFS_EXT2_4=y
BR2_TARGET_ROOTFS_EXT2_SIZE="128M"
BR2_TARGET_ROOTFS_CPIO=y
# BR2_TARGET_ROOTFS_TAR is not set
BR2_TARGET_UBOOT=y
BR2_TARGET_UBOOT_BUILD_SYSTEM_KCONFIG=y
@@ -37,24 +40,37 @@ class TestXen(infra.basetest.BRTest):
BR2_PACKAGE_HOST_MTOOLS=y
"""
def get_dom_uuid(self) -> str:
out, rc = self.emulator.run("cat /sys/hypervisor/uuid")
self.assertEqual(rc, 0, "Failed to get domain UUID")
return out[0]
def assertNumVM(self, x: int) -> None:
out, rc = self.emulator.run("xl vm-list")
self.assertEqual(rc, 0, "Failed to get VM list")
num_vm = len(out) - 1
self.assertEqual(num_vm, x, f"Expected {x} VM(s) but found {num_vm}")
def test_run(self):
uboot_bin = os.path.join(self.builddir, "images", "u-boot.bin")
disk_img = os.path.join(self.builddir, "images", "disk.img")
# We need to run Qemu with virtualization to run Xen.
qemu_opts = [
"-bios", uboot_bin,
"-cpu", "cortex-a53",
"-device", "virtio-blk-device,drive=hd0",
"-drive", f"file={disk_img},if=none,format=raw,id=hd0",
"-m", "2G",
"-m", "1G",
"-machine", "virt,gic-version=3,virtualization=on,acpi=off",
"-smp", "2"
]
# Boot the emulator:
# Qemu Devicetree -> U-Boot -> Xen UEFI -> Linux
self.emulator.boot(arch="aarch64",
options=qemu_opts)
# We need to boot Xen in UEFI to read xen.cfg; we use U-Boot as our
# UEFI firmware.
self.emulator.boot(arch="aarch64", options=qemu_opts)
self.emulator.login()
# Avoid double-cooking the terminal, otherwise the test infrastructure
@@ -63,3 +79,37 @@ class TestXen(infra.basetest.BRTest):
# Verify that we are indeed running under Xen.
self.assertRunOk("xl info")
# Check that we are dom0.
uuid = self.get_dom_uuid()
dom0_uuid = "00000000-0000-0000-0000-000000000000"
self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}")
# Check that we have one VM running.
self.assertNumVM(1)
# Create dom1 with console attached and login.
self.emulator.qemu.sendline("xl create -c /etc/xen/dom1.cfg")
self.emulator.login()
# Avoid double-cooking the terminal for dom1, too.
self.assertRunOk("stty raw")
# Check that we are not talking to dom0 anymore.
uuid = self.get_dom_uuid()
self.assertNotEqual(uuid, dom0_uuid, "Unexpected dom0 UUID")
# Detach from dom1's console with CTRL-].
# dom1 is still running in the background after that.
self.emulator.qemu.send(chr(0x1d))
mult = self.emulator.timeout_multiplier
index = self.emulator.qemu.expect(["#", pexpect.TIMEOUT],
timeout=2 * mult)
self.assertEqual(index, 0, "Timeout exiting guest")
# Check that we are talking to dom0 again.
uuid = self.get_dom_uuid()
self.assertEqual(uuid, dom0_uuid, f"Unexpected dom UUID {uuid}")
# Check that we have two VMs running.
self.assertNumVM(2)

View File

@@ -10,10 +10,11 @@ image efi-part.vfat {
files = {
"Image",
"rootfs.cpio"
}
}
size = 16M
size = 128M
}
image disk.img {
@@ -27,9 +28,4 @@ image disk.img {
offset = 32K
bootable = true
}
partition root {
partition-type-uuid = root-arm64
image = "rootfs.ext2"
}
}

View File

@@ -71,6 +71,9 @@ CONFIG_IOSCHED_BFQ=y
# CONFIG_SWAP is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_KSM=y
CONFIG_NET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_FW_LOADER_USER_HELPER=y

View File

@@ -0,0 +1,61 @@
#!/bin/sh
#
# Custom script for test_xen.py
# This will run both in dom0 and in dom1.
# When we detect that we are in dom0 we mount the boot partition under /mnt,
# to see the kernel image and the initramfs.
#
DAEMON="custom"
start() {
printf 'Starting %s: ' "$DAEMON"
case $(cat /sys/hypervisor/uuid) in
00000000-0000-0000-0000-000000000000)
printf "dom0 "
mount /dev/vda1 /mnt -o ro
;;
*) printf "domU " ;;
esac
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
case $(cat /sys/hypervisor/uuid) in
00000000-0000-0000-0000-000000000000)
printf "dom0 "
umount /mnt
;;
*) printf "domU " ;;
esac
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@@ -0,0 +1,5 @@
name="dom1"
kernel="/mnt/Image"
ramdisk="/mnt/rootfs.cpio"
memory=256
cmdline="console=hvc0"

View File

@@ -0,0 +1,7 @@
#!/bin/sh
set -eu
# Remove unnecessary Xen binaries to spare ramdisk size.
for ext in bin fd rom; do
rm -vf "${TARGET_DIR}/usr/share/qemu-xen/qemu/"*."$ext"
done

View File

@@ -1,2 +1,3 @@
options=dom0_mem=128M loglvl=all guest_loglvl=all
kernel=\Image root=PARTLABEL=root rootwait console=hvc0
options=dom0_mem=256M loglvl=all guest_loglvl=all
kernel=\Image console=hvc0
ramdisk=\rootfs.cpio