Forráskód Böngészése

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>
Vincent Stehlé 6 hónapja
szülő
commit
cd0ffd598c

+ 57 - 7
support/testing/tests/package/test_xen.py

@@ -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)

+ 2 - 6
support/testing/tests/package/test_xen/genimage.cfg

@@ -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"
-	}
 }

+ 3 - 0
support/testing/tests/package/test_xen/linux.config

@@ -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

+ 61 - 0
support/testing/tests/package/test_xen/overlay/etc/init.d/S99custom

@@ -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

+ 5 - 0
support/testing/tests/package/test_xen/overlay/etc/xen/dom1.cfg

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

+ 7 - 0
support/testing/tests/package/test_xen/post-build.sh

@@ -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

+ 3 - 2
support/testing/tests/package/test_xen/xen.cfg

@@ -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