From 56b1139ef2660535b112d0be4ddb2806f75298a8 Mon Sep 17 00:00:00 2001 From: Stephane Desneux Date: Mon, 23 May 2016 17:53:36 +0200 Subject: add layer meta-netboot to enable network boot over NBD (Network Block Device) To enable the build of network bootable images, the following line must be added to conf/local.conf: INHERIT += "netboot" This layer contains recipes for the following components: * busybox: activate the built-in NBD client * initramfs-netboot: contains the init script started by the kernel, responsible for mounting the remote root filesystem then pivoting and exec'ing systemd * initramfs-netboot-image: image to specify for building the initrd More details are available in meta-netboot/README. Bug-AGL: SPEC-175 Change-Id: Id2328dd9233d238cde77311e64e58344be244988 Signed-off-by: Stephane Desneux --- meta-netboot/README | 64 +++++++++ meta-netboot/README.porter | 41 ++++++ meta-netboot/classes/netboot.bbclass | 26 ++++ meta-netboot/conf/layer.conf | 10 ++ .../recipes-core/busybox/busybox_%.bbappend | 6 + .../recipes-core/busybox/files/enable_nbd.cfg | 1 + .../recipes-core/images/initramfs-netboot-image.bb | 19 +++ .../recipes-core/initramfs-netboot/files/init.sh | 149 +++++++++++++++++++++ .../initramfs-netboot/initramfs-netboot_1.0.bb | 19 +++ 9 files changed, 335 insertions(+) create mode 100644 meta-netboot/README create mode 100644 meta-netboot/README.porter create mode 100644 meta-netboot/classes/netboot.bbclass create mode 100644 meta-netboot/conf/layer.conf create mode 100644 meta-netboot/recipes-core/busybox/busybox_%.bbappend create mode 100644 meta-netboot/recipes-core/busybox/files/enable_nbd.cfg create mode 100644 meta-netboot/recipes-core/images/initramfs-netboot-image.bb create mode 100644 meta-netboot/recipes-core/initramfs-netboot/files/init.sh create mode 100644 meta-netboot/recipes-core/initramfs-netboot/initramfs-netboot_1.0.bb diff --git a/meta-netboot/README b/meta-netboot/README new file mode 100644 index 000000000..130477751 --- /dev/null +++ b/meta-netboot/README @@ -0,0 +1,64 @@ +meta-netboot +============ + +This layer contains some recipes and configuration adjustments to allow network boot through NBD (network block device). + +Content and usage +----------------- + +This layer creates a new supplementary initrd image which can be downloaded through TFTP with the kernel. +At boot time, the init script will try to mount the rootfs based on the following kernel command line parameters: +* nbd.server: IP address to reach the NBD server +* nbd.port: TCP port on which server is listening (default: 10809) +* nbd.dev: nbd device to use (default: /dev/nbd0) +* nbd.debug: activate debug mode (init script is then interruptible) + +The layer meta-netboot contains recipes for the following components: +* busybox: activate the built-in NBD client +* initramfs-netboot: contains the init script started by the kernel: basically, this script mounts the real root filesystem, then pivot_root on it and finally exec systemd. +* initramfs-netboot-image: image to specify for building the initrd + +To enable the build of the netboot initrd and ext4 rootfs, add the following line in conf/local.conf: + +INHERIT += "netboot" + + +Server side +----------- + +On the server side (assuming that the build dir is stored in $BUILD) we can run: + +* a TFTP server, for example tftpd-hpa started with $BUILD/tmp/deploy/images as the TFTP dir: + + /usr/sbin/in.tftpd --listen --user tftp --address 0.0.0.0:69 --secure $BUILD/tmp/deploy/images + +* a NBD server, for example xnbd-server, used to expose the whole ext4 rootfs as a network block device: + + xnbd-server --target --lport 10809 $BUILD/tmp/deploy/images/$MACHINE/agl-demo-platform-$MACHINE.ext4 + + +Target side +----------- + +On the target board, a specific setup should also be done. For example, for Renesas Porter board, the following U-boot environment could be used (adjust IP addresses !): + +------------------------------------------------------------------ +setenv 'bootkfile' 'uImage+dtb' +setenv 'bootkaddr' '0x40007fc0' +setenv 'bootifile' 'initramfs-netboot-image-porter.ext4.gz.u-boot' +setenv 'bootiaddr' '0x50000000' +setenv 'ipaddr' '' +setenv 'serverip' '' + +setenv 'bootargs_console' 'console=ttySC6,38400 ignore_loglevel' +setenv 'bootargs_video' 'vmalloc=384M video=HDMI-A-1:1280x960-32@60' +setenv 'bootargs_extra' 'rw rootfstype=ext4 rootwait rootdelay=2' +setenv 'bootargs_root' 'root=/dev/ram0 ramdisk_size=16384 ip=dhcp' +setenv 'bootkload_net' 'tftp ${bootkaddr} porter/${bootkfile}' +setenv 'bootiload_net' 'tftp ${bootiaddr} porter/${bootifile}' +setenv 'bootcmd' 'setenv bootargs ${bootargs_console} ${bootargs_video} ${bootargs_root} ${bootargs_extra} nbd.server=${serverip}; run bootkload_net; run bootiload_net; bootm ${bootkaddr} ${bootiaddr}' + +saveenv # optional: saves env in flash +run bootcmd # boots the board, executed automatically after power up +------------------------------------------------------------------ + diff --git a/meta-netboot/README.porter b/meta-netboot/README.porter new file mode 100644 index 000000000..7ab0803fb --- /dev/null +++ b/meta-netboot/README.porter @@ -0,0 +1,41 @@ +Below are the environment variables that can be set in the u-boot console to boot the porter board in various configurations + +################## Common options ##################### +# these options are common to all configurations: + +setenv 'bootkfile' 'uImage+dtb' +setenv 'bootkaddr' '0x40007fc0' + +setenv 'bootifile' 'initramfs-netboot-image-porter.ext4.gz.u-boot' +setenv 'bootiaddr' '0x50000000' + +setenv 'bootargs_console' 'console=ttySC6,38400 ignore_loglevel' +setenv 'bootargs_video' 'vmalloc=384M video=HDMI-A-1:1280x960-32@60' +setenv 'bootargs_extra' 'rw rootfstype=ext4 rootwait rootdelay=2' + +################ Boot on MMC (SDcard) ################# + +setenv 'bootargs_root' 'root=/dev/mmcblk0p1' +setenv 'bootmmc' '1:1' +setenv 'bootkload_sd' 'ext4load mmc ${bootmmc} ${bootkaddr} boot/${bootkfile}' +setenv 'bootcmd' 'setenv bootargs ${bootargs_console} ${bootargs_video} ${bootargs_root} ${bootargs_extra}; run bootkload_sd; bootm ${bootkaddr}' + +################ Boot on MMC (SDcard) with initrd ###### + +setenv 'bootargs_root' 'root=/dev/ram0 ramdisk_size=16384' +setenv 'bootmmc' '1:1' +setenv 'bootkload_sd' 'ext4load mmc ${bootmmc} ${bootkaddr} boot/${bootkfile}' +setenv 'bootiload_sd' 'ext4load mmc ${bootmmc} ${bootiaddr} boot/${bootifile}' +setenv 'bootcmd' 'setenv bootargs ${bootargs_console} ${bootargs_video} ${bootargs_root} ${bootargs_extra}; run bootkload_sd; run bootiload_sd; bootm ${bootkaddr} ${bootiaddr}' + +################ Netboot through TFTP+NBD ################## +# replace addresses by appropriate addresses + +setenv 'ipaddr' '' +setenv 'serverip' '' + +setenv 'bootargs_root' 'root=/dev/ram0 ramdisk_size=16384 ip=dhcp' +setenv 'bootkload_net' 'tftp ${bootkaddr} porter/${bootkfile}' +setenv 'bootiload_net' 'tftp ${bootiaddr} porter/${bootifile}' +setenv 'bootcmd' 'setenv bootargs ${bootargs_console} ${bootargs_video} ${bootargs_root} ${bootargs_extra} nbd.server=${serverip}; run bootkload_net; run bootiload_net; bootm ${bootkaddr} ${bootiaddr}' + diff --git a/meta-netboot/classes/netboot.bbclass b/meta-netboot/classes/netboot.bbclass new file mode 100644 index 000000000..0bb2452ad --- /dev/null +++ b/meta-netboot/classes/netboot.bbclass @@ -0,0 +1,26 @@ +# Enable network bootable image and initrd/initramfs + +# add image classes for uboot +IMAGE_CLASSES += "${@'image_types_uboot' if (d.getVar("KERNEL_IMAGETYPE", True) == "uImage") else ''}" + +python () { + d.appendVar("IMAGE_FSTYPES"," ext4") + + if (bb.utils.contains("IMAGE_FSTYPES","live",True,False,d)): + # typical case for Minnowboard Max + d.setVar("INITRD_IMAGE","initramfs-netboot-image") + d.setVar("INITRD","%s/%s-%s.ext4.gz" % ( + d.getVar("DEPLOY_DIR_IMAGE",True), + d.getVar("INITRD_IMAGE",True), + d.getVar("MACHINE",True) + )) + else: + d.appendVar("INITRAMFS_IMAGE"," initramfs-netboot-image") + if (d.getVar("KERNEL_IMAGETYPE",True) == "uImage"): + # case for "old" u-boot images, like Porter board + d.appendVar("INITRAMFS_FSTYPES"," ext4.gz.u-boot"); + else: + # case for new u-boot images which don't require uImage format + d.appendVar("INITRAMFS_FSTYPES"," ext4.gz"); +} + diff --git a/meta-netboot/conf/layer.conf b/meta-netboot/conf/layer.conf new file mode 100644 index 000000000..4077e6d66 --- /dev/null +++ b/meta-netboot/conf/layer.conf @@ -0,0 +1,10 @@ +# We have a conf and classes directory, add to BBPATH +BBPATH .= ":${LAYERDIR}" + +# We have recipes-* directories, add to BBFILES +BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \ + ${LAYERDIR}/recipes-*/*/*.bbappend" + +BBFILE_COLLECTIONS += "meta-netboot" +BBFILE_PATTERN_meta-netboot = "^${LAYERDIR}/" +BBFILE_PRIORITY_meta-netboot = "20" diff --git a/meta-netboot/recipes-core/busybox/busybox_%.bbappend b/meta-netboot/recipes-core/busybox/busybox_%.bbappend new file mode 100644 index 000000000..358913448 --- /dev/null +++ b/meta-netboot/recipes-core/busybox/busybox_%.bbappend @@ -0,0 +1,6 @@ +FILESEXTRAPATHS_prepend := "${THISDIR}/files:" + +SRC_URI += " \ + file://enable_nbd.cfg \ + " + diff --git a/meta-netboot/recipes-core/busybox/files/enable_nbd.cfg b/meta-netboot/recipes-core/busybox/files/enable_nbd.cfg new file mode 100644 index 000000000..7d6c7423f --- /dev/null +++ b/meta-netboot/recipes-core/busybox/files/enable_nbd.cfg @@ -0,0 +1 @@ +CONFIG_NBDCLIENT=y diff --git a/meta-netboot/recipes-core/images/initramfs-netboot-image.bb b/meta-netboot/recipes-core/images/initramfs-netboot-image.bb new file mode 100644 index 000000000..8b461e555 --- /dev/null +++ b/meta-netboot/recipes-core/images/initramfs-netboot-image.bb @@ -0,0 +1,19 @@ +# Netboot initramfs image. +DESCRIPTION = "Netboot initrd image" + +PACKAGE_INSTALL = "initramfs-netboot busybox base-passwd ${ROOTFS_BOOTSTRAP_INSTALL}" + +# Do not pollute the initrd image with rootfs features +IMAGE_FEATURES = "" + +export IMAGE_BASENAME = "initramfs-netboot-image" +IMAGE_LINGUAS = "" + +LICENSE = "MIT" + +IMAGE_FSTYPES = "${INITRAMFS_FSTYPES}" +inherit core-image + +IMAGE_ROOTFS_SIZE = "8192" + +BAD_RECOMMENDATIONS += "busybox-syslog" diff --git a/meta-netboot/recipes-core/initramfs-netboot/files/init.sh b/meta-netboot/recipes-core/initramfs-netboot/files/init.sh new file mode 100644 index 000000000..dae9a85cb --- /dev/null +++ b/meta-netboot/recipes-core/initramfs-netboot/files/init.sh @@ -0,0 +1,149 @@ +#!/bin/sh + +################################################################################ +# +# Init script to boot over network through NBD +# +# Contact: Stéphane Desneux +# +################################################################################ + +# banner generator: echo "AGL - Netboot" | figlet -f slant -w 80 -c +cat <<'EOF' >&2 +________________________________________________________________________________ + ___ ________ _ __ __ __ __ + / | / ____/ / / | / /__ / /_/ /_ ____ ____ / /_ + / /| |/ / __/ / ______ / |/ / _ \/ __/ __ \/ __ \/ __ \/ __/ + / ___ / /_/ / /___ /_____/ / /| / __/ /_/ /_/ / /_/ / /_/ / /_ + /_/ |_\____/_____/ /_/ |_/\___/\__/_.___/\____/\____/\__/ +________________________________________________________________________________ +EOF + +# global variables + +SMACK=n +NBD_SERVER= +NBD_PORT=10809 +NBD_DEV=/dev/nbd0 +DEBUG=n + +# ------------------------------------------- + +log_info() { echo "$0[$$]: $@" >&2; } +log_error() { echo "$0[$$]: ERROR $@" >&2; } + +do_mount_fs() { + log_info "mounting FS: $@" + [[ -e /proc/filesystems ]] && { grep -q "$1" /proc/filesystems || { log_error "Unknown filesystem"; return 1; } } + [[ -d "$2" ]] || mkdir -p "$2" + [[ -e /proc/mounts ]] && { grep -q -e "^$1 $2 $1" /proc/mounts && { log_info "$2 ($1) already mounted"; return 0; } } + mount -t "$1" "$1" "$2" +} + +bail_out() { + log_error "$@" + check_debug "Reboot will occur after exiting this shell." + log_info "Rebooting..." + exec reboot -f +} + +check_debug() { + case $DEBUG in + Y|y|yes|1|true) + log_info "$@" + /bin/sh -i + ;; + esac +} + +# ------------------------------------------- + +export PATH=/sbin:/usr/sbin:/bin:/usr/bin + +log_info "starting initrd script" + +do_mount_fs proc /proc +do_mount_fs sysfs /sys +do_mount_fs devtmpfs /dev +do_mount_fs devpts /dev/pts +do_mount_fs tmpfs /dev/shm +do_mount_fs tmpfs /tmp +do_mount_fs tmpfs /run + +# parse kernel commandline to get NBD server +for x in $(cat /proc/cmdline); do + case $x in + nbd.server=*) NBD_SERVER=${x/*=/};; + nbd.port=*) NBD_PORT=${x/*=/};; + nbd.dev=*) NBD_DEV=/dev/${x/*=/};; + nbd.debug=*) DEBUG=${x/*=/};; + esac +done + +check_debug "Debug point 1. Exit to continue initrd script (mount NBD device)." + +log_info "NBD parameters: device $NBD_DEV, server $NBD_SERVER:$NBD_PORT" + +# check if smack is active (and if so, mount smackfs) +grep -q smackfs /proc/filesystems && { + SMACK=y + + do_mount_fs smackfs /sys/fs/smackfs + + # adjust current label and network label + echo System >/proc/self/attr/current + echo System >/sys/fs/smackfs/ambient +} + +# start nbd client +try=5 +while :;do + log_info "Starting NBD client" + nbd-client $NBD_SERVER $NBD_PORT $NBD_DEV && { log_info "NBD client successfully started"; break; } + log_info "NBD client failed" + [[ $try -gt 0 ]] && { log_info "Retrying ($try trie(s) left)..."; sleep 3; try=$(( try - 1 )); continue; } + + bail_out "Unable to mount NBD device $NBD_DEV using server $NBD_SERVER:$NBD_PORT" +done + +# mount NBD device +mkdir -p /sysroot +mount $NBD_DEV /sysroot || bail_out "Unable to mount root NBD device" + +# move mounted devices to new root +cd /sysroot +for x in dev proc sys tmp run; do + log_info "Moving /$x to new rootfs" + mount -o move /$x $x +done + +# switch to new rootfs +log_info "Switching to new rootfs" +mkdir -p run/initramfs +pivot_root . run/initramfs || bail_out "pivot_root failed." + +# workaround for connman (avoid bringing down the network interface used for booting) +if [[ -f /lib/systemd/system/connman.service ]]; then + log_info "Adjusting Connman configuration" + iface=$(ip -o link show up | tr ':' ' ' | awk '{print $2}' | grep -v -e "^lo$" | head -1) + sed -i "s|connmand -n\$|connmand -n -I $iface|g" /lib/systemd/system/connman.service +fi + +# finally, run systemd +check_debug "Debug point 2. Exit to continue initrd script (run systemd)." + +log_info "Exec'ing systemd" +# banner generator: echo "AGL Booting . . ." | figlet -f slant -w 80 -c +cat <<'EOF' >&2 +________________________________________________________________________________ + ___ ________ ____ __ _ + / | / ____/ / / __ )____ ____ / /_(_)___ ____ _ + / /| |/ / __/ / / __ / __ \/ __ \/ __/ / __ \/ __ `/ + / ___ / /_/ / /___ / /_/ / /_/ / /_/ / /_/ / / / / /_/ / _ _ _ + /_/ |_\____/_____/ /_____/\____/\____/\__/_/_/ /_/\__, / (_) (_) (_) +_____________________________________________________/____/_____________________ +EOF + +exec /lib/systemd/systemd /dev/console 2>&1 +bail_out + diff --git a/meta-netboot/recipes-core/initramfs-netboot/initramfs-netboot_1.0.bb b/meta-netboot/recipes-core/initramfs-netboot/initramfs-netboot_1.0.bb new file mode 100644 index 000000000..5c85bee8f --- /dev/null +++ b/meta-netboot/recipes-core/initramfs-netboot/initramfs-netboot_1.0.bb @@ -0,0 +1,19 @@ +SUMMARY = "Extremely basic live image init script" +LICENSE = "MIT" +LIC_FILES_CHKSUM = "file://${COREBASE}/meta/COPYING.MIT;md5=3da9cfbcb788c80a0384361b4de20420" +SRC_URI = "file://init.sh" + +S = "${WORKDIR}" + +do_install() { + install -dm 0755 ${D}/etc + touch ${D}/etc/initrd-release + install -dm 0755 ${D}/dev + install -dm 0755 ${D}/sbin + install -m 0755 ${WORKDIR}/init.sh ${D}/sbin/init +} + +inherit allarch + +FILES_${PN} += " /dev /etc/initrd-release /sbin/init " + -- cgit 1.2.3-korg