summaryrefslogtreecommitdiffstats
path: root/recipes-core/vxn/vxn-initramfs-create.inc
diff options
context:
space:
mode:
authorBruce Ashfield <bruce.ashfield@gmail.com>2026-02-15 04:35:55 +0000
committerBruce Ashfield <bruce.ashfield@gmail.com>2026-02-26 01:05:01 +0000
commit57d267db7878180d1ecd1936df5284550d0031c3 (patch)
treeb2205ccb2e6114fdda4384518d4b9047209756ef /recipes-core/vxn/vxn-initramfs-create.inc
parent0fe8c4444f3199b862a4ba52b2b62b5f9b2af85f (diff)
downloadmeta-virtualization-57d267db7878180d1ecd1936df5284550d0031c3.tar.gz
vxn: add Xen DomU container runtime with OCI image support
vxn runs OCI containers as Xen DomU guests — the VM IS the container. No Docker/containerd runs inside the guest; the init script directly mounts the container rootfs and execs the entrypoint via chroot. Host-side (Dom0): - vxn.sh: Docker-like CLI wrapper (sets HYPERVISOR=xen) - vrunner-backend-xen.sh: Xen xl backend for vrunner - hv_prepare_container(): pulls OCI images via skopeo, resolves entrypoint from OCI config using jq on host - xl create for VM lifecycle (PVH on aarch64, PV on x86_64) - Bridge networking with iptables DNAT for port forwards - Console capture via xl console for ephemeral mode Guest-side (DomU): - vxn-init.sh: mounts container rootfs from input disk, extracts OCI layers, execs entrypoint via chroot - Supports containers with or without /bin/sh - grep/sed fallback for OCI config parsing (no jq needed) - Daemon mode with command loop on hvc1 - vcontainer-init-common.sh: hypervisor detection, head -n fix - vcontainer-preinit.sh: init selection via vcontainer.init= Build system: - vxn-initramfs-create.inc: assembles boot blobs from vruntime multiconfig, injects vxn-init.sh into rootfs squashfs - vxn_1.0.bb: Dom0 package with scripts + blobs - nostamp on install/package chain (blobs from DEPLOY_DIR are untracked by sstate) - vxn.cfg: Xen PV kernel config fragment Tested: vxn -it --no-daemon run --rm hello-world Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-core/vxn/vxn-initramfs-create.inc')
-rw-r--r--recipes-core/vxn/vxn-initramfs-create.inc223
1 files changed, 223 insertions, 0 deletions
diff --git a/recipes-core/vxn/vxn-initramfs-create.inc b/recipes-core/vxn/vxn-initramfs-create.inc
new file mode 100644
index 00000000..bde8bba9
--- /dev/null
+++ b/recipes-core/vxn/vxn-initramfs-create.inc
@@ -0,0 +1,223 @@
1# SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield
2#
3# SPDX-License-Identifier: MIT
4#
5# vxn-initramfs-create.inc
6# ===========================================================================
7# Shared code for building Xen DomU boot blobs for vxn
8# ===========================================================================
9#
10# This .inc file packages boot blobs for vxn (vcontainer on Xen).
11# It reuses the same initramfs and rootfs images built by vruntime
12# multiconfig (same images as vdkr/vpdmn), since the init scripts
13# detect the hypervisor at boot time.
14#
15# The kernel from vruntime already includes Xen PV support via vxn.cfg
16# fragment (added to DISTRO_FEATURES in vruntime.conf).
17#
18# Required variables from including recipe:
19# VXN_RUNTIME - runtime to source blobs from ("vdkr" or "vpdmn")
20#
21# Boot flow on Xen Dom0:
22# xl create <domain.cfg>
23# -> Xen boots kernel + tiny initramfs in DomU
24# -> preinit mounts rootfs.img from /dev/xvda
25# -> switch_root into rootfs.img
26# -> init detects Xen, uses /dev/xvd* and trans=xen
27#
28# ===========================================================================
29
30HOMEPAGE = "https://git.yoctoproject.org/meta-virtualization/"
31LICENSE = "MIT"
32LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
33
34inherit deploy
35
36EXCLUDE_FROM_WORLD = "1"
37DEPENDS = "squashfs-tools-native"
38
39# Default to vdkr (Docker) as the source runtime
40VXN_RUNTIME ?= "vdkr"
41
42# Always rebuild - init script injection must not be sstate-cached
43# because the rootfs.img content comes from the deploy dir (untracked)
44SSTATE_SKIP_CREATION = "1"
45do_compile[nostamp] = "1"
46do_deploy[nostamp] = "1"
47
48python () {
49
50 mc = d.getVar('VXN_MULTICONFIG')
51 runtime = d.getVar('VXN_RUNTIME')
52 bbmulticonfig = (d.getVar('BBMULTICONFIG') or "").split()
53 if mc in bbmulticonfig:
54 # All blobs come from the vruntime multiconfig - kernel, initramfs, rootfs
55 mcdeps = ' '.join([
56 'mc::%s:%s-tiny-initramfs-image:do_image_complete' % (mc, runtime),
57 'mc::%s:%s-rootfs-image:do_image_complete' % (mc, runtime),
58 'mc::%s:virtual/kernel:do_deploy' % mc,
59 ])
60 d.setVarFlag('do_compile', 'mcdepends', mcdeps)
61}
62
63INHIBIT_DEFAULT_DEPS = "1"
64
65# Init scripts to inject into the rootfs squashfs
66FILESEXTRAPATHS:prepend := "${THISDIR}/../../recipes-containers/vcontainer/files:"
67SRC_URI = "\
68 file://vxn-init.sh \
69 file://vcontainer-init-common.sh \
70"
71
72S = "${UNPACKDIR}"
73B = "${WORKDIR}/build"
74
75def vxn_get_kernel_image_name(d):
76 arch = d.getVar('TARGET_ARCH')
77 if arch == 'aarch64':
78 return 'Image'
79 elif arch in ['x86_64', 'i686', 'i586']:
80 return 'bzImage'
81 elif arch == 'arm':
82 return 'zImage'
83 return 'Image'
84
85def vxn_get_multiconfig_name(d):
86 arch = d.getVar('TARGET_ARCH')
87 if arch == 'aarch64':
88 return 'vruntime-aarch64'
89 elif arch in ['x86_64', 'i686', 'i586']:
90 return 'vruntime-x86-64'
91 return 'vruntime-aarch64'
92
93def vxn_get_blob_arch(d):
94 arch = d.getVar('TARGET_ARCH')
95 if arch == 'aarch64':
96 return 'aarch64'
97 elif arch in ['x86_64', 'i686', 'i586']:
98 return 'x86_64'
99 return 'aarch64'
100
101KERNEL_IMAGETYPE_INITRAMFS = "${@vxn_get_kernel_image_name(d)}"
102VXN_MULTICONFIG = "${@vxn_get_multiconfig_name(d)}"
103BLOB_ARCH = "${@vxn_get_blob_arch(d)}"
104
105VXN_MC_DEPLOY = "${TOPDIR}/tmp-${VXN_MULTICONFIG}/deploy/images/${MACHINE}"
106
107do_compile() {
108 mkdir -p ${B}
109
110 MC_TMPDIR="${TOPDIR}/tmp-${VXN_MULTICONFIG}"
111 MC_DEPLOY="${MC_TMPDIR}/deploy/images/${MACHINE}"
112
113 # =========================================================================
114 # PART 1: COPY TINY INITRAMFS (same as vdkr/vpdmn)
115 # =========================================================================
116 bbnote "Copying tiny initramfs from image build..."
117
118 INITRAMFS_SRC="${MC_DEPLOY}/${VXN_RUNTIME}-tiny-initramfs-image-${MACHINE}.cpio.gz"
119
120 if [ ! -f "${INITRAMFS_SRC}" ]; then
121 bbfatal "Initramfs not found at ${INITRAMFS_SRC}. Build it first with: bitbake mc:${VXN_MULTICONFIG}:${VXN_RUNTIME}-tiny-initramfs-image"
122 fi
123
124 cp "${INITRAMFS_SRC}" ${B}/initramfs.cpio.gz
125 INITRAMFS_SIZE=$(stat -c%s ${B}/initramfs.cpio.gz)
126 bbnote "Initramfs copied: ${INITRAMFS_SIZE} bytes ($(expr ${INITRAMFS_SIZE} / 1024)KB)"
127
128 # =========================================================================
129 # PART 2: COPY ROOTFS (same squashfs, works under both QEMU and Xen)
130 # =========================================================================
131 bbnote "Copying rootfs from image build..."
132
133 ROOTFS_SRC="${MC_DEPLOY}/${VXN_RUNTIME}-rootfs-image-${MACHINE}.rootfs.squashfs"
134
135 if [ ! -f "${ROOTFS_SRC}" ]; then
136 bbfatal "Rootfs image not found at ${ROOTFS_SRC}. Build it first with: bitbake mc:${VXN_MULTICONFIG}:${VXN_RUNTIME}-rootfs-image"
137 fi
138
139 cp "${ROOTFS_SRC}" ${B}/rootfs.img
140 ROOTFS_SIZE=$(stat -c%s ${B}/rootfs.img)
141 bbnote "Rootfs image copied: ${ROOTFS_SIZE} bytes ($(expr ${ROOTFS_SIZE} / 1024 / 1024)MB)"
142
143 # Inject vxn init scripts into the rootfs squashfs
144 bbnote "Injecting vxn init scripts into rootfs..."
145 UNSQUASH_DIR="${B}/rootfs-unsquash"
146 rm -rf "${UNSQUASH_DIR}"
147 unsquashfs -d "${UNSQUASH_DIR}" ${B}/rootfs.img
148 install -m 0755 ${S}/vxn-init.sh ${UNSQUASH_DIR}/vxn-init.sh
149 install -m 0755 ${S}/vcontainer-init-common.sh ${UNSQUASH_DIR}/vcontainer-init-common.sh
150 rm -f ${B}/rootfs.img
151 mksquashfs "${UNSQUASH_DIR}" ${B}/rootfs.img -noappend -comp xz
152 rm -rf "${UNSQUASH_DIR}"
153 ROOTFS_SIZE=$(stat -c%s ${B}/rootfs.img)
154 bbnote "Rootfs with vxn init scripts: ${ROOTFS_SIZE} bytes ($(expr ${ROOTFS_SIZE} / 1024 / 1024)MB)"
155
156 # =========================================================================
157 # PART 3: COPY KERNEL (Xen PV-capable via vxn.cfg fragment)
158 # =========================================================================
159 bbnote "Copying kernel image..."
160 KERNEL_FILE="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE_INITRAMFS}"
161 if [ -f "${KERNEL_FILE}" ]; then
162 cp "${KERNEL_FILE}" ${B}/kernel
163 KERNEL_SIZE=$(stat -c%s ${B}/kernel)
164 bbnote "Kernel copied: ${KERNEL_SIZE} bytes ($(expr ${KERNEL_SIZE} / 1024 / 1024)MB)"
165 else
166 bbwarn "Kernel not found at ${KERNEL_FILE}"
167 fi
168}
169
170# This is a deploy-only recipe - no packages produced.
171# PACKAGES="" prevents the rootfs task from looking for package manifests.
172PACKAGES = ""
173do_install[noexec] = "1"
174do_package[noexec] = "1"
175do_packagedata[noexec] = "1"
176do_package_write_rpm[noexec] = "1"
177do_package_write_ipk[noexec] = "1"
178do_package_write_deb[noexec] = "1"
179do_populate_sysroot[noexec] = "1"
180
181do_deploy() {
182 install -d ${DEPLOYDIR}/vxn/${BLOB_ARCH}
183
184 if [ -f ${B}/initramfs.cpio.gz ]; then
185 install -m 0644 ${B}/initramfs.cpio.gz ${DEPLOYDIR}/vxn/${BLOB_ARCH}/
186 bbnote "Deployed initramfs.cpio.gz to vxn/${BLOB_ARCH}/"
187 fi
188
189 if [ -f ${B}/rootfs.img ]; then
190 install -m 0644 ${B}/rootfs.img ${DEPLOYDIR}/vxn/${BLOB_ARCH}/
191 bbnote "Deployed rootfs.img to vxn/${BLOB_ARCH}/"
192 fi
193
194 if [ -f ${B}/kernel ]; then
195 install -m 0644 ${B}/kernel ${DEPLOYDIR}/vxn/${BLOB_ARCH}/${KERNEL_IMAGETYPE_INITRAMFS}
196 bbnote "Deployed kernel as vxn/${BLOB_ARCH}/${KERNEL_IMAGETYPE_INITRAMFS}"
197 fi
198
199 cat > ${DEPLOYDIR}/vxn/${BLOB_ARCH}/README << EOF
200vxn Boot Blobs (Xen DomU)
201==========================
202
203Built for: ${TARGET_ARCH}
204Machine: ${MACHINE}
205Multiconfig: ${VXN_MULTICONFIG}
206Source runtime: ${VXN_RUNTIME}
207Date: $(date)
208
209Files:
210 ${KERNEL_IMAGETYPE_INITRAMFS} - Kernel image (Xen PV-capable)
211 initramfs.cpio.gz - Tiny initramfs (busybox + preinit)
212 rootfs.img - Root filesystem with container tools
213
214Boot flow:
215 xl create <domain.cfg>
216 -> Xen boots kernel + initramfs in DomU
217 -> preinit detects Xen, mounts rootfs.img from /dev/xvda
218 -> switch_root into rootfs.img
219 -> init script runs container commands
220EOF
221}
222
223addtask deploy after do_compile before do_build