From d2238e728783be3f1f254e93554f9e0a51fd2556 Mon Sep 17 00:00:00 2001 From: Bruce Ashfield Date: Tue, 12 Nov 2024 20:02:30 +0000 Subject: [PATCH] xen: enable networking and guest image bundling The xen host image reference needed signifant work to be functional for launching and testing Xen domu guests. Here we add additional tools to the host image, and allow it to automatically bundle guests if the configuration is enabled. We also add systemd networking configuration to create a xenbr0 which offeres connectivity to the entire reference system. See the recipes and the README for details on testing and bundling. Signed-off-by: Bruce Ashfield --- classes/virt_networking.bbclass | 26 +++ .../images/xen-guest-image-minimal.bb | 28 ++- recipes-extended/images/xen-image-minimal.bb | 181 +++++++++++++++++- recipes-extended/xen/files/10-ether.network | 5 + recipes-extended/xen/files/10-xenbr0.netdev | 3 + recipes-extended/xen/files/10-xenbr0.network | 5 + recipes-extended/xen/xen-tools.inc | 10 + 7 files changed, 249 insertions(+), 9 deletions(-) create mode 100644 classes/virt_networking.bbclass create mode 100644 recipes-extended/xen/files/10-ether.network create mode 100644 recipes-extended/xen/files/10-xenbr0.netdev create mode 100644 recipes-extended/xen/files/10-xenbr0.network diff --git a/classes/virt_networking.bbclass b/classes/virt_networking.bbclass new file mode 100644 index 00000000..e92e1de5 --- /dev/null +++ b/classes/virt_networking.bbclass @@ -0,0 +1,26 @@ +# Similarly to the cni_networking.bbclass this class should be +# inherted by recipes to produce a package that contains their +# desired networking configuration. +# +# Currently only systemd networking is supported, but this will +# be extended in the future +# +# By simply specifying the configuration / networking files, +# they will be package and then eventually installed to the +# correct target location. +# +PACKAGES:prepend = "${PN}-net-conf " +FILES:${PN}-net-conf = "${sysconfdir}/systemd/network/*" + +do_install:append() { + if [ -z "${VIRT_NETWORKING_FILES}" ]; then + bbfatal "virt-networking was inherited, but no networking configuration was provided via VIRT_NETWORKING_FILES" + fi + + # TODO: possibily make the systemd configuration conditional on the init manager + install -d "${D}/${sysconfdir}/systemd/network/" + for f in ${VIRT_NETWORKING_FILES}; do + conf_name="$(basename $f)" + install -D -m 0644 "$f" "${D}/${sysconfdir}/systemd/network/$conf_name" + done +} diff --git a/recipes-extended/images/xen-guest-image-minimal.bb b/recipes-extended/images/xen-guest-image-minimal.bb index fced7639..76f320e4 100644 --- a/recipes-extended/images/xen-guest-image-minimal.bb +++ b/recipes-extended/images/xen-guest-image-minimal.bb @@ -1,6 +1,7 @@ DESCRIPTION = "A Xen guest image." -inherit core-image features_check +inherit core-image features_check deploy +inherit kernel-artifact-names IMAGE_INSTALL += " \ packagegroup-core-boot \ @@ -23,3 +24,28 @@ LICENSE = "MIT" # Send console messages to xen console APPEND += "console=hvc0" + +IMAGE_FSTYPES = "tar.bz2 ext4 ext4.qcow2" + +XEN_GUEST_AUTO_BUNDLE ?= "" + +# When a xen-guest-image-minimal is built with the +# XEN_GUEST_AUTO_BUNDLE varaible set to True, a configuration file for +# automatic guest bundling will be generated and the guest bundled +# automatically when a xen host image is built. +do_deploy() { + if [ -n "${XEN_GUEST_AUTO_BUNDLE}" ]; then + outname="xen-guest-bundle-${IMAGE_BASENAME}${IMAGE_MACHINE_SUFFIX}-${IMAGE_VERSION_SUFFIX}.cfg" +cat <>${DEPLOYDIR}/$outname +name = "xen-guest" +memory = 512 +vcpus = 1 +disk = ['file:${IMAGE_LINK_NAME}.ext4,xvda,rw'] +vif = ['bridge=xenbr0'] +kernel = "${KERNEL_IMAGETYPE}" +extra = "root=/dev/xvda ro ip=dhcp" +EOF + fi +} + +addtask deploy after do_compile diff --git a/recipes-extended/images/xen-image-minimal.bb b/recipes-extended/images/xen-image-minimal.bb index e6fa93ca..866212ed 100644 --- a/recipes-extended/images/xen-image-minimal.bb +++ b/recipes-extended/images/xen-image-minimal.bb @@ -1,9 +1,14 @@ DESCRIPTION = "A minimal xen image" +inherit features_check + +REQUIRED_DISTRO_FEATURES ?= "xen systemd" + INITRD_IMAGE = "core-image-minimal-initramfs" XEN_KERNEL_MODULES ?= "kernel-module-xen-blkback kernel-module-xen-gntalloc \ kernel-module-xen-gntdev kernel-module-xen-netback kernel-module-xen-wdt \ + kernel-module-xt-comment kernel-module-xt-masquerade \ ${@bb.utils.contains('MACHINE_FEATURES', 'pci', "${XEN_PCIBACK_MODULE}", '', d)} \ ${@bb.utils.contains('MACHINE_FEATURES', 'acpi', '${XEN_ACPI_PROCESSOR_MODULE}', '', d)} \ " @@ -16,6 +21,7 @@ IMAGE_INSTALL += " \ qemu \ kernel-image \ kernel-vmlinux \ + rsync \ " # The hypervisor may not be within the dom0 filesystem image but at least @@ -44,14 +50,6 @@ QB_QEMU_CLASSES = "" QB_QEMU_CLASSES:qemuall = "qemuboot-xen-defaults qemuboot-xen-dtb qemuboot-testimage-network" inherit ${QB_QEMU_CLASSES} -do_check_xen_state() { - if [ "${@bb.utils.contains('DISTRO_FEATURES', 'xen', ' yes', 'no', d)}" = "no" ]; then - die "DISTRO_FEATURES does not contain 'xen'" - fi -} - -addtask check_xen_state before do_rootfs - # note: this may be unused, see the wic plugin syslinux_iso_populate:append() { install -m 0444 ${STAGING_DATADIR}/syslinux/libcom32.c32 ${ISODIR}${ISOLINUXDIR} @@ -88,6 +86,168 @@ build_syslinux_cfg () { echo " APPEND /xen.gz ${SYSLINUX_XEN_ARGS} --- /vmlinuz ${SYSLINUX_KERNEL_ARGS} --- /initrd" >> ${SYSLINUX_CFG} } +# Function to parse the config file and get values for specific keys +get_config_value() { + config_file="$1" + key="$2" + line=$(grep -w "$key" $config_file) + value=$(echo "$line" | cut -d '=' -f 2-) + # Remove quotes, leading/trailing whitespace, and content after the first comma + echo "${value#*=}" | sed "s/'//g; s/^\s*|\s*$//g; s/\[//g;s/\"//g;s/^ *//g;" | cut -d ',' -f 1 +} + +generate_guest_config() { + name=$1 + kernel=$2 + disk=$3 + outname=$name.cfg + + cat <${DEPLOY_DIR_IMAGE}/$outname +name = "$name" +memory = 512 +vcpus = 1 +disk = ['file:$disk,xvda,rw'] +vif = ['bridge=xenbr0'] +kernel = "$kernel" +extra = "root=/dev/xvda ro ip=dhcp" +EOF +} + +# Guests can be bundled automatically through the following mechanisms: +# +# - via the variable XEN_BUNDLED_GUESTS +# - via a xen configuration file in the deploy directory of the format +# xen-guest-bundle-*.cfg +# +# The guests can be built via OE, or be 3rd party guests. They just +# must be in the deploy directory so they can be copied into the rootfs +# of the xen host image +# +# Type 1) XEN_BUNDLED_GUESTS +# +# If XEN_BUNDLED_GUESTS is used, it is simply a colon separated list of +# rootfs:kernels. Normal variable rules apply, so it can be set in a +# local.conf, or in a bbappend to the image recipe. +# +# An example would be: +# +# XEN_BUNDLED_GUESTS = "xen-guest-image-minimal-qemuarm64.rootfs.ext4:Image" +# +# These point at symlinks created in the image deploy directory, or they +# can be specific images/kernels without the symlink. +# +# Type 2) A Xen guest configuration file +# +# If xen guest configuration files are found in the deploy directories +# the kernel and disk information contained within them will be processed +# and modified for the xen host. The kernel and guest image will be +# copied to the appropriate location, and the config made to match. +# +# These files following the naming convention: xen-guest-bundle*.cfg +# +# Guests of type #1 generate a configuration file that is picked up as +# type #2. +# +# An example config file follows: +# +## name = "xen-guest" +## memory = 512 +## vcpus = 1 +## disk = ['file:xen-guest-image-minimal-qemuarm64.rootfs.ext4,xvda,rw'] +## vif = ['bridge=xenbr0'] +## kernel = "Image" +## extra = "root=/dev/xvda ro console=hvc0 ip=dhcp" +# +# It should also be noted that when a xen-guest-image-minimal is built +# with the XEN_GUEST_AUTO_BUNDLE varaible set to True, a configuration +# file for type #2 will be generated and the guest bundled automatically +# when the host image is built. +# +# kernel and rootfs are copied to the target in /var/lib/xen/images/ +# +# configuration files are copied to: /etc/xen +# +# Guests can be launched after boot with: xl create -c /etc/xen/ +# +bundle_xen_guests() { + set -e + + if [ -n "${XEN_BUNDLED_GUESTS}" ]; then + echo "Processing Xen bundled guests variable: ${XEN_BUNDLED_GUESTS}" + # these are a colon separated list of rootfs:kernel + count=1 + for g in ${XEN_BUNDLED_GUESTS}; do + echo "Guest line: $g" + rootfs=$(echo "$g" | cut -d":" -f1) + kernel=$(echo "$g" | cut -d":" -f2) + name="xen-guest-bundle-$count" + + if ! [ -e ${DEPLOY_DIR_IMAGE}/$rootfs ]; then + echo "rootfs '${DEPLOY_DIR_IMAGE}/$rootfs' not found, skipping ...." + continue + fi + if ! [ -e ${DEPLOY_DIR_IMAGE}/$kernel ]; then + echo "kernel '${DEPLOY_DIR_IMAGE}/$kernel' not found, skipping ...." + continue + fi + + generate_guest_config $name $kernel $rootfs + + count=$(expr $count + 1) + done + fi + + echo ls ${DEPLOY_DIR_IMAGE}/xen-guest-bundle*.cfg + ls ${DEPLOY_DIR_IMAGE}/xen-guest-bundle*.cfg >/dev/null 2>/dev/null + if [ $? -eq 0 ]; then + for guest_cfg in $(ls ${DEPLOY_DIR_IMAGE}/xen-guest-bundle*.cfg); do + echo "Bundling guest: $guest_cfg" + + CONFIG_FILE_BASE=$(basename $guest_cfg .cfg) + CONFIG_FILE="${DEPLOY_DIR_IMAGE}/$CONFIG_FILE_BASE.cfg" + DEST_DIR="${IMAGE_ROOTFS}/var/lib/xen/images" + MODIFIED_CONFIG_FILE="${DEPLOY_DIR_IMAGE}/$CONFIG_FILE_BASE-modified.cfg" + + # Extract values from the configuration file + DISK_ORIG=$(get_config_value $CONFIG_FILE "disk" | sed 's/file://g') + DISK=$(readlink -f ${DEPLOY_DIR_IMAGE}/$DISK_ORIG) + DISK_NAME=$(basename $DISK) + KERNEL_ORIG=$(get_config_value $CONFIG_FILE "kernel") + KERNEL=$(readlink -f ${DEPLOY_DIR_IMAGE}/$KERNEL_ORIG) + KERNEL_NAME=$(basename $KERNEL) + + if [ -z "$DISK" ]; then + echo "rootfs '$DISK' not found, skipping ...." + continue + fi + if [ -z "$KERNEL" ]; then + echo "kernel '$KERNEL' not found, skipping ...." + continue + fi + + mkdir -p "$DEST_DIR" + # Copy the disk and kernel to the destination directory + echo "Copying disk and kernel files..." + echo cp "$DISK" "$DEST_DIR" + echo cp "$KERNEL" "$DEST_DIR" + cp "$DISK" "$DEST_DIR" + cp "$KERNEL" "$DEST_DIR" + + # Create a modified config file with updated paths + sed -E \ + -e "s#^(disk = \[)[^,]+#\1'file:/var/lib/xen/images/$DISK_NAME#" \ + -e "s#^(kernel = )\"[^\"]+\"#\1\"/var/lib/xen/images/$KERNEL_NAME\"#" \ + "$CONFIG_FILE" > "$MODIFIED_CONFIG_FILE" + + mkdir -p ${IMAGE_ROOTFS}/etc/xen + cp $MODIFIED_CONFIG_FILE ${IMAGE_ROOTFS}/etc/xen/$CONFIG_FILE_BASE.cfg + rm -f $MODIFIED_CONFIG_FILE + done + fi + # exit 1 +} +ROOTFS_POSTPROCESS_COMMAND += "bundle_xen_guests;" + # Enable runqemu. eg: runqemu xen-image-minimal nographic slirp WKS_FILE:x86-64 = "directdisk-xen.wks" WKS_FILE_DEPENDS_DEFAULT:x86-64 = "syslinux-native" @@ -107,3 +267,8 @@ do_image_wic[depends] += "xen:do_deploy" # and so does the emulated e1000 -- choose according to the network device # drivers that are present in your dom0 Linux kernel. To switch to e1000: # QB_NETWORK_DEVICE = "-device e1000,netdev=net0,mac=@MAC@" + + +IMAGE_ROOTFS_SIZE = "8192" +# we always need extra space to install VMs, so add 2GB +IMAGE_ROOTFS_EXTRA_SPACE = "2000000" diff --git a/recipes-extended/xen/files/10-ether.network b/recipes-extended/xen/files/10-ether.network new file mode 100644 index 00000000..8d27ca92 --- /dev/null +++ b/recipes-extended/xen/files/10-ether.network @@ -0,0 +1,5 @@ +[Match] +Type=ether + +[Network] +Bridge=xenbr0 diff --git a/recipes-extended/xen/files/10-xenbr0.netdev b/recipes-extended/xen/files/10-xenbr0.netdev new file mode 100644 index 00000000..ec45879f --- /dev/null +++ b/recipes-extended/xen/files/10-xenbr0.netdev @@ -0,0 +1,3 @@ +[NetDev] +Name=xenbr0 +Kind=bridge diff --git a/recipes-extended/xen/files/10-xenbr0.network b/recipes-extended/xen/files/10-xenbr0.network new file mode 100644 index 00000000..1e10c3eb --- /dev/null +++ b/recipes-extended/xen/files/10-xenbr0.network @@ -0,0 +1,5 @@ +[Match] +Name=xenbr0 + +[Network] +DHCP=yes diff --git a/recipes-extended/xen/xen-tools.inc b/recipes-extended/xen/xen-tools.inc index 35dbb493..fba10b04 100644 --- a/recipes-extended/xen/xen-tools.inc +++ b/recipes-extended/xen/xen-tools.inc @@ -6,6 +6,15 @@ COMPATIBLE_HOST = 'i686-.*-linux|(x86_64.*).*-linux|aarch64.*-linux|arm-.*-linux inherit setuptools3 update-rc.d systemd deploy require xen-blktap.inc +SRC_URI += "file://10-ether.network \ + file://10-xenbr0.netdev \ + file://10-xenbr0.network" + +VIRT_NETWORKING_FILES = "${UNPACKDIR}/10-ether.network \ + ${UNPACKDIR}/10-xenbr0.netdev \ + ${UNPACKDIR}/10-xenbr0.network" +inherit virt_networking + QEMU_SYSTEM ?= "qemu-system-i386" QEMU_SYSTEM_RDEPENDS ?= "${QEMU_SYSTEM} qemu-firmware" @@ -30,6 +39,7 @@ RDEPENDS:${PN} = "\ virtual-xenstored \ ${PN}-xl \ ${QEMU_SYSTEM_RDEPENDS} \ + ${PN}-net-conf \ " RDEPENDS:${PN}-dev = ""