run-tests.sh 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/env bash
  2. # Test the current package under a different kernel.
  3. # Requires virtme and qemu to be installed.
  4. # Examples:
  5. # Run all tests on a 5.4 kernel
  6. # $ ./run-tests.sh 5.4
  7. # Run a subset of tests:
  8. # $ ./run-tests.sh 5.4 ./link
  9. set -euo pipefail
  10. script="$(realpath "$0")"
  11. readonly script
  12. # This script is a bit like a Matryoshka doll since it keeps re-executing itself
  13. # in various different contexts:
  14. #
  15. # 1. invoked by the user like run-tests.sh 5.4
  16. # 2. invoked by go test like run-tests.sh --exec-vm
  17. # 3. invoked by init in the vm like run-tests.sh --exec-test
  18. #
  19. # This allows us to use all available CPU on the host machine to compile our
  20. # code, and then only use the VM to execute the test. This is because the VM
  21. # is usually slower at compiling than the host.
  22. if [[ "${1:-}" = "--exec-vm" ]]; then
  23. shift
  24. input="$1"
  25. shift
  26. # Use sudo if /dev/kvm isn't accessible by the current user.
  27. sudo=""
  28. if [[ ! -r /dev/kvm || ! -w /dev/kvm ]]; then
  29. sudo="sudo"
  30. fi
  31. readonly sudo
  32. testdir="$(dirname "$1")"
  33. output="$(mktemp -d)"
  34. printf -v cmd "%q " "$@"
  35. if [[ "$(stat -c '%t:%T' -L /proc/$$/fd/0)" == "1:3" ]]; then
  36. # stdin is /dev/null, which doesn't play well with qemu. Use a fifo as a
  37. # blocking substitute.
  38. mkfifo "${output}/fake-stdin"
  39. # Open for reading and writing to avoid blocking.
  40. exec 0<> "${output}/fake-stdin"
  41. rm "${output}/fake-stdin"
  42. fi
  43. for ((i = 0; i < 3; i++)); do
  44. if ! $sudo virtme-run --kimg "${input}/bzImage" --memory 768M --pwd \
  45. --rwdir="${testdir}=${testdir}" \
  46. --rodir=/run/input="${input}" \
  47. --rwdir=/run/output="${output}" \
  48. --script-sh "PATH=\"$PATH\" CI_MAX_KERNEL_VERSION="${CI_MAX_KERNEL_VERSION:-}" \"$script\" --exec-test $cmd" \
  49. --kopt possible_cpus=2; then # need at least two CPUs for some tests
  50. exit 23
  51. fi
  52. if [[ -e "${output}/status" ]]; then
  53. break
  54. fi
  55. if [[ -v CI ]]; then
  56. echo "Retrying test run due to qemu crash"
  57. continue
  58. fi
  59. exit 42
  60. done
  61. rc=$(<"${output}/status")
  62. $sudo rm -r "$output"
  63. exit $rc
  64. elif [[ "${1:-}" = "--exec-test" ]]; then
  65. shift
  66. mount -t bpf bpf /sys/fs/bpf
  67. mount -t tracefs tracefs /sys/kernel/debug/tracing
  68. if [[ -d "/run/input/bpf" ]]; then
  69. export KERNEL_SELFTESTS="/run/input/bpf"
  70. fi
  71. if [[ -f "/run/input/bpf/bpf_testmod/bpf_testmod.ko" ]]; then
  72. insmod "/run/input/bpf/bpf_testmod/bpf_testmod.ko"
  73. fi
  74. dmesg --clear
  75. rc=0
  76. "$@" || rc=$?
  77. dmesg
  78. echo $rc > "/run/output/status"
  79. exit $rc # this return code is "swallowed" by qemu
  80. fi
  81. readonly kernel_version="${1:-}"
  82. if [[ -z "${kernel_version}" ]]; then
  83. echo "Expecting kernel version as first argument"
  84. exit 1
  85. fi
  86. shift
  87. readonly kernel="linux-${kernel_version}.bz"
  88. readonly selftests="linux-${kernel_version}-selftests-bpf.tgz"
  89. readonly input="$(mktemp -d)"
  90. readonly tmp_dir="${TMPDIR:-/tmp}"
  91. readonly branch="${BRANCH:-master}"
  92. fetch() {
  93. echo Fetching "${1}"
  94. pushd "${tmp_dir}" > /dev/null
  95. curl -s -L -O --fail --etag-compare "${1}.etag" --etag-save "${1}.etag" "https://github.com/cilium/ci-kernels/raw/${branch}/${1}"
  96. local ret=$?
  97. popd > /dev/null
  98. return $ret
  99. }
  100. fetch "${kernel}"
  101. cp "${tmp_dir}/${kernel}" "${input}/bzImage"
  102. if fetch "${selftests}"; then
  103. echo "Decompressing selftests"
  104. mkdir "${input}/bpf"
  105. tar --strip-components=4 -xf "${tmp_dir}/${selftests}" -C "${input}/bpf"
  106. else
  107. echo "No selftests found, disabling"
  108. fi
  109. args=(-short -coverpkg=./... -coverprofile=coverage.out -count 1 ./...)
  110. if (( $# > 0 )); then
  111. args=("$@")
  112. fi
  113. export GOFLAGS=-mod=readonly
  114. export CGO_ENABLED=0
  115. # LINUX_VERSION_CODE test compares this to discovered value.
  116. export KERNEL_VERSION="${kernel_version}"
  117. echo Testing on "${kernel_version}"
  118. go test -exec "$script --exec-vm $input" "${args[@]}"
  119. echo "Test successful on ${kernel_version}"
  120. rm -r "${input}"