#!/bin/bash # SPDX-License-Identifier: GPL-2.0 set -u set -e # This script currently only works for x86_64, as # it is based on the VM image used by the BPF CI which is # x86_64. QEMU_BINARY="${QEMU_BINARY:="qemu-system-x86_64"}" X86_BZIMAGE="arch/x86/boot/bzImage" DEFAULT_COMMAND="./test_progs" MOUNT_DIR="mnt" ROOTFS_IMAGE="root.img" OUTPUT_DIR="$HOME/.bpf_selftests" KCONFIG_URL="https://raw.githubusercontent.com/libbpf/libbpf/master/travis-ci/vmtest/configs/latest.config" KCONFIG_API_URL="https://api.github.com/repos/libbpf/libbpf/contents/travis-ci/vmtest/configs/latest.config" INDEX_URL="https://raw.githubusercontent.com/libbpf/libbpf/master/travis-ci/vmtest/configs/INDEX" NUM_COMPILE_JOBS="$(nproc)" LOG_FILE_BASE="$(date +"bpf_selftests.%Y-%m-%d_%H-%M-%S")" LOG_FILE="${LOG_FILE_BASE}.log" EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status" usage() { cat <] -- [] is the command you would normally run when you are in tools/testing/selftests/bpf. e.g: $0 -- ./test_progs -t test_lsm If no command is specified and a debug shell (-s) is not requested, "${DEFAULT_COMMAND}" will be run by default. If you build your kernel using KBUILD_OUTPUT= or O= options, these can be passed as environment variables to the script: O= $0 -- ./test_progs -t test_lsm or KBUILD_OUTPUT= $0 -- ./test_progs -t test_lsm Options: -i) Update the rootfs image with a newer version. -d) Update the output directory (default: ${OUTPUT_DIR}) -j) Number of jobs for compilation, similar to -j in make (default: ${NUM_COMPILE_JOBS}) -s) Instead of powering off the VM, start an interactive shell. If is specified, the shell runs after the command finishes executing EOF } unset URLS populate_url_map() { if ! declare -p URLS &> /dev/null; then # URLS contain the mapping from file names to URLs where # those files can be downloaded from. declare -gA URLS while IFS=$'\t' read -r name url; do URLS["$name"]="$url" done < <(curl -Lsf ${INDEX_URL}) fi } download() { local file="$1" if [[ ! -v URLS[$file] ]]; then echo "$file not found" >&2 return 1 fi echo "Downloading $file..." >&2 curl -Lsf "${URLS[$file]}" "${@:2}" } newest_rootfs_version() { { for file in "${!URLS[@]}"; do if [[ $file =~ ^libbpf-vmtest-rootfs-(.*)\.tar\.zst$ ]]; then echo "${BASH_REMATCH[1]}" fi done } | sort -rV | head -1 } download_rootfs() { local rootfsversion="$1" local dir="$2" if ! which zstd &> /dev/null; then echo 'Could not find "zstd" on the system, please install zstd' exit 1 fi download "libbpf-vmtest-rootfs-$rootfsversion.tar.zst" | zstd -d | sudo tar -C "$dir" -x } recompile_kernel() { local kernel_checkout="$1" local make_command="$2" cd "${kernel_checkout}" ${make_command} olddefconfig ${make_command} } mount_image() { local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}" local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}" sudo mount -o loop "${rootfs_img}" "${mount_dir}" } unmount_image() { local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}" sudo umount "${mount_dir}" &> /dev/null } update_selftests() { local kernel_checkout="$1" local selftests_dir="${kernel_checkout}/tools/testing/selftests/bpf" cd "${selftests_dir}" ${make_command} # Mount the image and copy the selftests to the image. mount_image sudo rm -rf "${mount_dir}/root/bpf" sudo cp -r "${selftests_dir}" "${mount_dir}/root" unmount_image } update_init_script() { local init_script_dir="${OUTPUT_DIR}/${MOUNT_DIR}/etc/rcS.d" local init_script="${init_script_dir}/S50-startup" local command="$1" local exit_command="$2" mount_image if [[ ! -d "${init_script_dir}" ]]; then cat < ${init_script}" if [[ "${command}" != "" ]]; then sudo bash -c "cat >>${init_script}" < "/root/${EXIT_STATUS_FILE}" { cd /root/bpf echo ${command} stdbuf -oL -eL ${command} echo "\$?" > "/root/${EXIT_STATUS_FILE}" } 2>&1 | tee "/root/${LOG_FILE}" # Ensure that the logs are written to disk sync EOF fi sudo bash -c "echo ${exit_command} >> ${init_script}" sudo chmod a+x "${init_script}" unmount_image } create_vm_image() { local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}" local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}" rm -rf "${rootfs_img}" touch "${rootfs_img}" chattr +C "${rootfs_img}" >/dev/null 2>&1 || true truncate -s 2G "${rootfs_img}" mkfs.ext4 -q "${rootfs_img}" mount_image download_rootfs "$(newest_rootfs_version)" "${mount_dir}" unmount_image } run_vm() { local kernel_bzimage="$1" local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}" if ! which "${QEMU_BINARY}" &> /dev/null; then cat <