Naveen Joy | 7ea7ab5 | 2021-05-11 10:31:18 -0700 | [diff] [blame] | 1 | #!/usr/bin/env bash |
| 2 | # Run VPP in a QEMU VM |
| 3 | # set -o xtrace |
| 4 | set -o nounset |
| 5 | |
| 6 | # Arguments: |
| 7 | # $1:- Test Filter |
| 8 | # $2:- Kernel Image |
| 9 | # $3:- Test Data Directory |
| 10 | # $4:- CPU Mask String (e.g. "5,6,7,8") |
| 11 | # $5:- Guest MEM in Gibibytes (e.g. 2G) |
| 12 | |
| 13 | if [[ -z "${1:-}" ]]; then |
| 14 | echo "ERROR: A non-empty test selection is required to run |
| 15 | tests in a QEMU VM" |
| 16 | exit 1 |
| 17 | fi |
| 18 | TEST=${1:-} |
| 19 | TEST_JOBS=${TEST_JOBS:-1} |
| 20 | |
| 21 | # Init RAM disk image to boot the QEMU VM |
| 22 | INITRD=${INITRD:-} |
| 23 | |
| 24 | # Ensure test dir |
| 25 | TEST_DATA_DIR=${3:-"/tmp/vpp-vm-tests"} |
| 26 | if [[ ! -d ${TEST_DATA_DIR} ]]; then |
| 27 | mkdir -p ${TEST_DATA_DIR} |
| 28 | fi |
| 29 | |
| 30 | # CPU Affinity for taskset |
| 31 | CPU_MASK=${4:-"5,6,7,8"} |
| 32 | IFS=',' read -r -a CPU_MASK_ARRAY <<< ${CPU_MASK} |
| 33 | CPUS=${#CPU_MASK_ARRAY[@]} |
| 34 | |
| 35 | # Guest MEM (Default 2G) |
| 36 | MEM=${5:-"2G"} |
| 37 | |
| 38 | # Set the QEMU executable for the OS pkg. |
| 39 | os_VENDOR=$(lsb_release -i -s) |
| 40 | if [[ $os_VENDOR =~ (Debian|Ubuntu) ]]; then |
| 41 | os_PACKAGE="deb" |
| 42 | QEMU=${QEMU:-"qemu-system-x86_64"} |
| 43 | else |
| 44 | os_PACKAGE="rpm" |
| 45 | QEMU=${QEMU:-"qemu-kvm"} |
| 46 | fi |
| 47 | |
| 48 | # Exit if the ${QEMU} executable is not available |
| 49 | if ! command -v ${QEMU} &> /dev/null; then |
| 50 | echo "Error: ${QEMU} is required, but could not be found." |
| 51 | exit 1 |
| 52 | fi |
| 53 | |
| 54 | # Download the Generic Linux Kernel, if needed |
| 55 | if [[ -z "${2:-}" ]] || [[ ! -f "${2:-}" ]]; then |
| 56 | if [[ $os_PACKAGE == "deb" ]]; then |
| 57 | PWD=$(pwd) |
| 58 | cd ${TEST_DATA_DIR} |
| 59 | PKG="linux-image-$(uname -r)" |
| 60 | echo "Getting the Linux Kernel image..${PKG}" |
| 61 | apt-get download ${PKG} |
| 62 | dpkg --fsys-tarfile ${PKG}_*.deb | tar xvf - ./boot |
| 63 | KERNEL_BIN=$(ls ${TEST_DATA_DIR}/boot/vmlinuz-*-generic) |
| 64 | cd ${PWD} |
| 65 | else |
| 66 | echo "ERROR: Kernel Image selection is required for RPM pkgs." |
| 67 | exit 1 |
| 68 | fi |
| 69 | else |
| 70 | KERNEL_BIN=${2:-} |
| 71 | fi |
| 72 | |
| 73 | ## Create initrd with 9p drivers, if ${INITRD} is null |
| 74 | DRIVERS_9P="" |
| 75 | if [[ -z "${INITRD}" ]] && [[ ! -d "/etc/initramfs-tools" ]]; then |
| 76 | echo "To boot the QEMU VM, an initial RAM disk with 9p drivers is needed" |
| 77 | echo "Install the initramfs-tools package or set env var INITRD to the RAM disk path" |
| 78 | exit 1 |
| 79 | elif [[ -z "${INITRD}" ]]; then |
| 80 | if [[ -f "/etc/initramfs-tools/modules" ]]; then |
| 81 | DRIVERS_9P=$(grep 9p /etc/initramfs-tools/modules | awk '{print $1}' | cut -d$'\n' -f1) |
| 82 | fi |
| 83 | if [[ -z "${DRIVERS_9P}" ]]; then |
| 84 | echo "You'll need to update the file /etc/initramfs-tools/modules with the below 9p drivers" |
| 85 | echo "9p >> /etc/initramfs-tools/modules" |
| 86 | echo "9pnet >> /etc/initramfs-tools/modules" |
| 87 | echo "9pnet_virtio >> /etc/initramfs-tools/modules" |
| 88 | exit 1 |
| 89 | fi |
| 90 | # Generate the initramfs image, if the we haven't generated one yet |
| 91 | if ! ls ${TEST_DATA_DIR}/boot/initrd.img-*-generic &> /dev/null; then |
| 92 | echo "Generating a bootable initramfs image in ${TEST_DATA_DIR}/boot/" |
| 93 | update-initramfs -c -k $(uname -r) -b ${TEST_DATA_DIR}/boot >/dev/null 2>&1 |
| 94 | echo "Generated the INITRD image" |
| 95 | fi |
| 96 | INITRD=$(ls ${TEST_DATA_DIR}/boot/initrd.img-*-generic) |
| 97 | fi |
| 98 | echo "Using INITRD=${TEST_DATA_DIR}/boot/${INITRD} for booting the QEMU VM" |
| 99 | |
| 100 | |
| 101 | ## Install iperf into ${TEST_DATA_DIR} |
| 102 | IPERF=${TEST_DATA_DIR}/usr/bin/iperf |
| 103 | if [[ ! -x ${IPERF} ]] && [[ $os_PACKAGE == "deb" ]]; then |
| 104 | echo "Installing iperf: ${IPERF}" |
| 105 | PWD=$(pwd) |
| 106 | cd ${TEST_DATA_DIR} |
| 107 | IPRF_PKG="iperf_2.0.5+dfsg1-2_amd64.deb" |
| 108 | wget https://iperf.fr/download/ubuntu/${IPRF_PKG} |
| 109 | dpkg --fsys-tarfile ${IPRF_PKG} | tar xvf - |
| 110 | if [[ -x ${IPERF} ]]; then |
| 111 | echo "${IPERF} installed successfully" |
| 112 | else |
| 113 | echo "ERROR: iperf executable ${IPERF} installation failed" |
| 114 | exit 1 |
| 115 | fi |
| 116 | cd ${PWD} |
| 117 | elif [[ ! -x ${IPERF} ]] && [[ $os_PACKAGE != "deb" ]]; then |
| 118 | echo "ERROR: install iperf: ${IPERF} before running QEMU tests" |
| 119 | exit 1 |
| 120 | fi |
| 121 | |
| 122 | FAILED_DIR=${FAILED_DIR:-"/tmp/vpp-failed-unittests/"} |
| 123 | if [[ ! -d ${FAILED_DIR} ]]; then |
| 124 | mkdir -p ${FAILED_DIR} |
| 125 | fi |
| 126 | |
| 127 | HUGEPAGES=${HUGEPAGES:-256} |
| 128 | |
| 129 | # Ensure all required Env vars are bound to non-zero values |
| 130 | EnvVarArray=("WS_ROOT=${WS_ROOT:-}" |
| 131 | "RND_SEED=${RND_SEED:-}" |
| 132 | "BR=${BR:-}" |
| 133 | "VENV_PATH=${VENV_PATH:-}" |
| 134 | "VPP_BUILD_DIR=${VPP_BUILD_DIR:-}" |
| 135 | "VPP_BIN=${VPP_BIN:-}" |
| 136 | "VPP_PLUGIN_PATH=${VPP_PLUGIN_PATH:-}" |
| 137 | "VPP_TEST_PLUGIN_PATH=${VPP_TEST_PLUGIN_PATH:-}" |
| 138 | "VPP_INSTALL_PATH=${VPP_INSTALL_PATH:-}" |
| 139 | "LD_LIBRARY_PATH=${LD_LIBRARY_PATH:-}") |
| 140 | |
| 141 | for envVar in ${EnvVarArray[*]}; do |
| 142 | var_name=$(echo $envVar | cut -d= -f1) |
| 143 | var_val=$(echo $envVar | cut -d= -f2) |
| 144 | if [[ -z "$var_val" ]]; then |
| 145 | echo "ERROR: Env var: $var_name is not set" |
| 146 | exit 1 |
| 147 | fi |
| 148 | done |
| 149 | |
| 150 | # Boot QEMU VM and run the test |
| 151 | function run_in_vm { |
| 152 | INIT=$(mktemp -p ${TEST_DATA_DIR}) |
| 153 | cat > ${INIT} << _EOF_ |
| 154 | #!/bin/bash |
| 155 | mkdir -p /dev/shm |
| 156 | mount -t tmpfs -o rw,nosuid,nodev tmpfs /dev/shm |
| 157 | mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true |
| 158 | mount -t tmpfs -o "noexec,nosuid,size=10%,mode=0755" tmpfs /run |
| 159 | mount -t 9p /dev/vpp9p ${WS_ROOT} |
| 160 | mount -t 9p tmp9p /tmp |
| 161 | modprobe -a vhost_net |
| 162 | env SOCKET=1 SANITY=no \ |
| 163 | FAILED_DIR=${FAILED_DIR} RND_SEED=${RND_SEED} BR=${BR} \ |
| 164 | VENV_PATH=${VENV_PATH} TEST=${TEST} TEST_JOBS=${TEST_JOBS} \ |
| 165 | VPP_BUILD_DIR=${VPP_BUILD_DIR} VPP_BIN=${VPP_BIN} VPP_PLUGIN_PATH=${VPP_PLUGIN_PATH} \ |
| 166 | VPP_TEST_PLUGIN_PATH=${VPP_TEST_PLUGIN_PATH} VPP_INSTALL_PATH=${VPP_INSTALL_PATH} \ |
| 167 | LD_LIBRARY_PATH=${LD_LIBRARY_PATH} TEST_DATA_DIR=${TEST_DATA_DIR} INITRD=${INITRD} \ |
| 168 | bash -c "${WS_ROOT}/test/scripts/run.sh --filter=${TEST} --jobs=${TEST_JOBS} --failed-dir=${FAILED_DIR} \ |
| 169 | --venv-dir=${VENV_PATH} --vpp-ws-dir=${WS_ROOT} --extended" |
| 170 | poweroff -f |
| 171 | _EOF_ |
| 172 | |
| 173 | chmod +x ${INIT} |
| 174 | |
| 175 | sudo taskset -c ${CPU_MASK} ${QEMU} \ |
| 176 | -nodefaults \ |
| 177 | -name test_$(basename $INIT) \ |
| 178 | -chardev stdio,mux=on,id=char0 \ |
| 179 | -mon chardev=char0,mode=readline,pretty=on \ |
| 180 | -serial chardev:char0 \ |
| 181 | -machine pc,accel=kvm,usb=off,mem-merge=off \ |
| 182 | -cpu host \ |
| 183 | -smp ${CPUS},sockets=1,cores=${CPUS},threads=1 \ |
| 184 | -m ${MEM} \ |
| 185 | -no-user-config \ |
| 186 | -kernel ${KERNEL_BIN} \ |
| 187 | -initrd ${INITRD} \ |
| 188 | -fsdev local,id=root9p,path=/,security_model=none,multidevs=remap \ |
| 189 | -device virtio-9p-pci,fsdev=root9p,mount_tag=fsRoot \ |
| 190 | -virtfs local,path=${WS_ROOT},mount_tag=/dev/vpp9p,security_model=none,id=vpp9p,multidevs=remap \ |
| 191 | -virtfs local,path=/tmp,mount_tag=tmp9p,security_model=passthrough,id=tmp9p,multidevs=remap \ |
| 192 | -netdev tap,id=net0,vhost=on \ |
| 193 | -device virtio-net-pci,netdev=net0,mac=52:54:00:de:64:01 \ |
| 194 | -nographic \ |
| 195 | -append "ro root=fsRoot rootfstype=9p rootflags=trans=virtio,cache=mmap console=ttyS0 hugepages=${HUGEPAGES} init=${INIT}" |
| 196 | } |
| 197 | |
| 198 | run_in_vm |