~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/vmtest.sh

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #!/bin/bash
  2 # SPDX-License-Identifier: GPL-2.0
  3 
  4 set -e
  5 
  6 # This script currently only works for the following platforms,
  7 # as it is based on the VM image used by the BPF CI, which is
  8 # available only for these architectures. We can also specify
  9 # the local rootfs image generated by the following script:
 10 # https://github.com/libbpf/ci/blob/main/rootfs/mkrootfs_debian.sh
 11 PLATFORM="${PLATFORM:-$(uname -m)}"
 12 case "${PLATFORM}" in
 13 s390x)
 14         QEMU_BINARY=qemu-system-s390x
 15         QEMU_CONSOLE="ttyS1"
 16         HOST_FLAGS=(-smp 2 -enable-kvm)
 17         CROSS_FLAGS=(-smp 2)
 18         BZIMAGE="arch/s390/boot/vmlinux"
 19         ARCH="s390"
 20         ;;
 21 x86_64)
 22         QEMU_BINARY=qemu-system-x86_64
 23         QEMU_CONSOLE="ttyS0,115200"
 24         HOST_FLAGS=(-cpu host -enable-kvm -smp 8)
 25         CROSS_FLAGS=(-smp 8)
 26         BZIMAGE="arch/x86/boot/bzImage"
 27         ARCH="x86"
 28         ;;
 29 aarch64)
 30         QEMU_BINARY=qemu-system-aarch64
 31         QEMU_CONSOLE="ttyAMA0,115200"
 32         HOST_FLAGS=(-M virt,gic-version=3 -cpu host -enable-kvm -smp 8)
 33         CROSS_FLAGS=(-M virt,gic-version=3 -cpu cortex-a76 -smp 8)
 34         BZIMAGE="arch/arm64/boot/Image"
 35         ARCH="arm64"
 36         ;;
 37 riscv64)
 38         # required qemu version v7.2.0+
 39         QEMU_BINARY=qemu-system-riscv64
 40         QEMU_CONSOLE="ttyS0,115200"
 41         HOST_FLAGS=(-M virt -cpu host -enable-kvm -smp 8)
 42         CROSS_FLAGS=(-M virt -cpu rv64,sscofpmf=true -smp 8)
 43         BZIMAGE="arch/riscv/boot/Image"
 44         ARCH="riscv"
 45         ;;
 46 *)
 47         echo "Unsupported architecture"
 48         exit 1
 49         ;;
 50 esac
 51 DEFAULT_COMMAND="./test_progs"
 52 MOUNT_DIR="mnt"
 53 LOCAL_ROOTFS_IMAGE=""
 54 ROOTFS_IMAGE="root.img"
 55 OUTPUT_DIR="$HOME/.bpf_selftests"
 56 KCONFIG_REL_PATHS=("tools/testing/selftests/bpf/config"
 57         "tools/testing/selftests/bpf/config.vm"
 58         "tools/testing/selftests/bpf/config.${PLATFORM}")
 59 INDEX_URL="https://raw.githubusercontent.com/libbpf/ci/master/INDEX"
 60 NUM_COMPILE_JOBS="$(nproc)"
 61 LOG_FILE_BASE="$(date +"bpf_selftests.%Y-%m-%d_%H-%M-%S")"
 62 LOG_FILE="${LOG_FILE_BASE}.log"
 63 EXIT_STATUS_FILE="${LOG_FILE_BASE}.exit_status"
 64 
 65 usage()
 66 {
 67         cat <<EOF
 68 Usage: $0 [-i] [-s] [-d <output_dir>] -- [<command>]
 69 
 70 <command> is the command you would normally run when you are in
 71 tools/testing/selftests/bpf. e.g:
 72 
 73         $0 -- ./test_progs -t test_lsm
 74 
 75 If no command is specified and a debug shell (-s) is not requested,
 76 "${DEFAULT_COMMAND}" will be run by default.
 77 
 78 Using PLATFORM= and CROSS_COMPILE= options will enable cross platform testing:
 79 
 80   PLATFORM=<platform> CROSS_COMPILE=<toolchain> $0 -- ./test_progs -t test_lsm
 81 
 82 If you build your kernel using KBUILD_OUTPUT= or O= options, these
 83 can be passed as environment variables to the script:
 84 
 85   O=<kernel_build_path> $0 -- ./test_progs -t test_lsm
 86 
 87 or
 88 
 89   KBUILD_OUTPUT=<kernel_build_path> $0 -- ./test_progs -t test_lsm
 90 
 91 Options:
 92 
 93         -l)             Specify the path to the local rootfs image.
 94         -i)             Update the rootfs image with a newer version.
 95         -d)             Update the output directory (default: ${OUTPUT_DIR})
 96         -j)             Number of jobs for compilation, similar to -j in make
 97                         (default: ${NUM_COMPILE_JOBS})
 98         -s)             Instead of powering off the VM, start an interactive
 99                         shell. If <command> is specified, the shell runs after
100                         the command finishes executing
101 EOF
102 }
103 
104 unset URLS
105 populate_url_map()
106 {
107         if ! declare -p URLS &> /dev/null; then
108                 # URLS contain the mapping from file names to URLs where
109                 # those files can be downloaded from.
110                 declare -gA URLS
111                 while IFS=$'\t' read -r name url; do
112                         URLS["$name"]="$url"
113                 done < <(curl -Lsf ${INDEX_URL})
114         fi
115 }
116 
117 newest_rootfs_version()
118 {
119         {
120         for file in "${!URLS[@]}"; do
121                 if [[ $file =~ ^"${PLATFORM}"/libbpf-vmtest-rootfs-(.*)\.tar\.zst$ ]]; then
122                         echo "${BASH_REMATCH[1]}"
123                 fi
124         done
125         } | sort -rV | head -1
126 }
127 
128 download_rootfs()
129 {
130         populate_url_map
131 
132         local rootfsversion="$(newest_rootfs_version)"
133         local file="${PLATFORM}/libbpf-vmtest-rootfs-$rootfsversion.tar.zst"
134 
135         if [[ ! -v URLS[$file] ]]; then
136                 echo "$file not found" >&2
137                 return 1
138         fi
139 
140         echo "Downloading $file..." >&2
141         curl -Lsf "${URLS[$file]}" "${@:2}"
142 }
143 
144 load_rootfs()
145 {
146         local dir="$1"
147 
148         if ! which zstd &> /dev/null; then
149                 echo 'Could not find "zstd" on the system, please install zstd'
150                 exit 1
151         fi
152 
153         if [[ -n "${LOCAL_ROOTFS_IMAGE}" ]]; then
154                 cat "${LOCAL_ROOTFS_IMAGE}" | zstd -d | sudo tar -C "$dir" -x
155         else
156                 download_rootfs | zstd -d | sudo tar -C "$dir" -x
157         fi
158 }
159 
160 recompile_kernel()
161 {
162         local kernel_checkout="$1"
163         local make_command="$2"
164 
165         cd "${kernel_checkout}"
166 
167         ${make_command} olddefconfig
168         ${make_command}
169 }
170 
171 mount_image()
172 {
173         local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}"
174         local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
175 
176         sudo mount -o loop "${rootfs_img}" "${mount_dir}"
177 }
178 
179 unmount_image()
180 {
181         local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
182 
183         sudo umount "${mount_dir}" &> /dev/null
184 }
185 
186 update_selftests()
187 {
188         local kernel_checkout="$1"
189         local selftests_dir="${kernel_checkout}/tools/testing/selftests/bpf"
190 
191         cd "${selftests_dir}"
192         ${make_command}
193 
194         # Mount the image and copy the selftests to the image.
195         mount_image
196         sudo rm -rf "${mount_dir}/root/bpf"
197         sudo cp -r "${selftests_dir}" "${mount_dir}/root"
198         unmount_image
199 }
200 
201 update_init_script()
202 {
203         local init_script_dir="${OUTPUT_DIR}/${MOUNT_DIR}/etc/rcS.d"
204         local init_script="${init_script_dir}/S50-startup"
205         local command="$1"
206         local exit_command="$2"
207 
208         mount_image
209 
210         if [[ ! -d "${init_script_dir}" ]]; then
211                 cat <<EOF
212 Could not find ${init_script_dir} in the mounted image.
213 This likely indicates a bad rootfs image, Please download
214 a new image by passing "-i" to the script
215 EOF
216                 exit 1
217 
218         fi
219 
220         sudo bash -c "echo '#!/bin/bash' > ${init_script}"
221 
222         if [[ "${command}" != "" ]]; then
223                 sudo bash -c "cat >>${init_script}" <<EOF
224 # Have a default value in the exit status file
225 # incase the VM is forcefully stopped.
226 echo "130" > "/root/${EXIT_STATUS_FILE}"
227 
228 {
229         cd /root/bpf
230         echo ${command}
231         stdbuf -oL -eL ${command}
232         echo "\$?" > "/root/${EXIT_STATUS_FILE}"
233 } 2>&1 | tee "/root/${LOG_FILE}"
234 # Ensure that the logs are written to disk
235 sync
236 EOF
237         fi
238 
239         sudo bash -c "echo ${exit_command} >> ${init_script}"
240         sudo chmod a+x "${init_script}"
241         unmount_image
242 }
243 
244 create_vm_image()
245 {
246         local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}"
247         local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
248 
249         rm -rf "${rootfs_img}"
250         touch "${rootfs_img}"
251         chattr +C "${rootfs_img}" >/dev/null 2>&1 || true
252 
253         truncate -s 2G "${rootfs_img}"
254         mkfs.ext4 -q "${rootfs_img}"
255 
256         mount_image
257         load_rootfs "${mount_dir}"
258         unmount_image
259 }
260 
261 run_vm()
262 {
263         local kernel_bzimage="$1"
264         local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}"
265 
266         if ! which "${QEMU_BINARY}" &> /dev/null; then
267                 cat <<EOF
268 Could not find ${QEMU_BINARY}
269 Please install qemu or set the QEMU_BINARY environment variable.
270 EOF
271                 exit 1
272         fi
273 
274         if [[ "${PLATFORM}" != "$(uname -m)" ]]; then
275                 QEMU_FLAGS=("${CROSS_FLAGS[@]}")
276         else
277                 QEMU_FLAGS=("${HOST_FLAGS[@]}")
278         fi
279 
280         ${QEMU_BINARY} \
281                 -nodefaults \
282                 -display none \
283                 -serial mon:stdio \
284                 "${QEMU_FLAGS[@]}" \
285                 -m 4G \
286                 -drive file="${rootfs_img}",format=raw,index=1,media=disk,if=virtio,cache=none \
287                 -kernel "${kernel_bzimage}" \
288                 -append "root=/dev/vda rw console=${QEMU_CONSOLE}"
289 }
290 
291 copy_logs()
292 {
293         local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
294         local log_file="${mount_dir}/root/${LOG_FILE}"
295         local exit_status_file="${mount_dir}/root/${EXIT_STATUS_FILE}"
296 
297         mount_image
298         sudo cp ${log_file} "${OUTPUT_DIR}"
299         sudo cp ${exit_status_file} "${OUTPUT_DIR}"
300         sudo rm -f ${log_file}
301         unmount_image
302 }
303 
304 is_rel_path()
305 {
306         local path="$1"
307 
308         [[ ${path:0:1} != "/" ]]
309 }
310 
311 do_update_kconfig()
312 {
313         local kernel_checkout="$1"
314         local kconfig_file="$2"
315 
316         rm -f "$kconfig_file" 2> /dev/null
317 
318         for config in "${KCONFIG_REL_PATHS[@]}"; do
319                 local kconfig_src="${kernel_checkout}/${config}"
320                 cat "$kconfig_src" >> "$kconfig_file"
321         done
322 }
323 
324 update_kconfig()
325 {
326         local kernel_checkout="$1"
327         local kconfig_file="$2"
328 
329         if [[ -f "${kconfig_file}" ]]; then
330                 local local_modified="$(stat -c %Y "${kconfig_file}")"
331 
332                 for config in "${KCONFIG_REL_PATHS[@]}"; do
333                         local kconfig_src="${kernel_checkout}/${config}"
334                         local src_modified="$(stat -c %Y "${kconfig_src}")"
335                         # Only update the config if it has been updated after the
336                         # previously cached config was created. This avoids
337                         # unnecessarily compiling the kernel and selftests.
338                         if [[ "${src_modified}" -gt "${local_modified}" ]]; then
339                                 do_update_kconfig "$kernel_checkout" "$kconfig_file"
340                                 # Once we have found one outdated configuration
341                                 # there is no need to check other ones.
342                                 break
343                         fi
344                 done
345         else
346                 do_update_kconfig "$kernel_checkout" "$kconfig_file"
347         fi
348 }
349 
350 catch()
351 {
352         local exit_code=$1
353         local exit_status_file="${OUTPUT_DIR}/${EXIT_STATUS_FILE}"
354         # This is just a cleanup and the directory may
355         # have already been unmounted. So, don't let this
356         # clobber the error code we intend to return.
357         unmount_image || true
358         if [[ -f "${exit_status_file}" ]]; then
359                 exit_code="$(cat ${exit_status_file})"
360         fi
361         exit ${exit_code}
362 }
363 
364 main()
365 {
366         local script_dir="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
367         local kernel_checkout=$(realpath "${script_dir}"/../../../../)
368         # By default the script searches for the kernel in the checkout directory but
369         # it also obeys environment variables O= and KBUILD_OUTPUT=
370         local kernel_bzimage="${kernel_checkout}/${BZIMAGE}"
371         local command="${DEFAULT_COMMAND}"
372         local update_image="no"
373         local exit_command="poweroff -f"
374         local debug_shell="no"
375 
376         while getopts ':hskl:id:j:' opt; do
377                 case ${opt} in
378                 l)
379                         LOCAL_ROOTFS_IMAGE="$OPTARG"
380                         ;;
381                 i)
382                         update_image="yes"
383                         ;;
384                 d)
385                         OUTPUT_DIR="$OPTARG"
386                         ;;
387                 j)
388                         NUM_COMPILE_JOBS="$OPTARG"
389                         ;;
390                 s)
391                         command=""
392                         debug_shell="yes"
393                         exit_command="bash"
394                         ;;
395                 h)
396                         usage
397                         exit 0
398                         ;;
399                 \? )
400                         echo "Invalid Option: -$OPTARG"
401                         usage
402                         exit 1
403                         ;;
404                 : )
405                         echo "Invalid Option: -$OPTARG requires an argument"
406                         usage
407                         exit 1
408                         ;;
409                 esac
410         done
411         shift $((OPTIND -1))
412 
413         trap 'catch "$?"' EXIT
414 
415         if [[ "${PLATFORM}" != "$(uname -m)" ]] && [[ -z "${CROSS_COMPILE}" ]]; then
416                 echo "Cross-platform testing needs to specify CROSS_COMPILE"
417                 exit 1
418         fi
419 
420         if [[ $# -eq 0  && "${debug_shell}" == "no" ]]; then
421                 echo "No command specified, will run ${DEFAULT_COMMAND} in the vm"
422         else
423                 command="$@"
424         fi
425 
426         local kconfig_file="${OUTPUT_DIR}/latest.config"
427         local make_command="make ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} \
428                             -j ${NUM_COMPILE_JOBS} KCONFIG_CONFIG=${kconfig_file}"
429 
430         # Figure out where the kernel is being built.
431         # O takes precedence over KBUILD_OUTPUT.
432         if [[ "${O:=""}" != "" ]]; then
433                 if is_rel_path "${O}"; then
434                         O="$(realpath "${PWD}/${O}")"
435                 fi
436                 kernel_bzimage="${O}/${BZIMAGE}"
437                 make_command="${make_command} O=${O}"
438         elif [[ "${KBUILD_OUTPUT:=""}" != "" ]]; then
439                 if is_rel_path "${KBUILD_OUTPUT}"; then
440                         KBUILD_OUTPUT="$(realpath "${PWD}/${KBUILD_OUTPUT}")"
441                 fi
442                 kernel_bzimage="${KBUILD_OUTPUT}/${BZIMAGE}"
443                 make_command="${make_command} KBUILD_OUTPUT=${KBUILD_OUTPUT}"
444         fi
445 
446         local rootfs_img="${OUTPUT_DIR}/${ROOTFS_IMAGE}"
447         local mount_dir="${OUTPUT_DIR}/${MOUNT_DIR}"
448 
449         echo "Output directory: ${OUTPUT_DIR}"
450 
451         mkdir -p "${OUTPUT_DIR}"
452         mkdir -p "${mount_dir}"
453         update_kconfig "${kernel_checkout}" "${kconfig_file}"
454 
455         recompile_kernel "${kernel_checkout}" "${make_command}"
456 
457         if [[ "${update_image}" == "no" && ! -f "${rootfs_img}" ]]; then
458                 echo "rootfs image not found in ${rootfs_img}"
459                 update_image="yes"
460         fi
461 
462         if [[ "${update_image}" == "yes" ]]; then
463                 create_vm_image
464         fi
465 
466         update_selftests "${kernel_checkout}" "${make_command}"
467         update_init_script "${command}" "${exit_command}"
468         run_vm "${kernel_bzimage}"
469         if [[ "${command}" != "" ]]; then
470                 copy_logs
471                 echo "Logs saved in ${OUTPUT_DIR}/${LOG_FILE}"
472         fi
473 }
474 
475 main "$@"

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php