summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/vsock/vmtest.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/vsock/vmtest.sh')
-rwxr-xr-xtools/testing/selftests/vsock/vmtest.sh346
1 files changed, 233 insertions, 113 deletions
diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh
index 8ceeb8a7894f..c7b270dd77a9 100755
--- a/tools/testing/selftests/vsock/vmtest.sh
+++ b/tools/testing/selftests/vsock/vmtest.sh
@@ -7,6 +7,8 @@
# * virtme-ng
# * busybox-static (used by virtme-ng)
# * qemu (used by virtme-ng)
+#
+# shellcheck disable=SC2317,SC2119
readonly SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly KERNEL_CHECKOUT=$(realpath "${SCRIPT_DIR}"/../../../../)
@@ -22,8 +24,9 @@ readonly SSH_HOST_PORT=2222
readonly VSOCK_CID=1234
readonly WAIT_PERIOD=3
readonly WAIT_PERIOD_MAX=60
-readonly WAIT_TOTAL=$(( WAIT_PERIOD * WAIT_PERIOD_MAX ))
-readonly QEMU_PIDFILE=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
+readonly WAIT_QEMU=5
+readonly PIDFILE_TEMPLATE=/tmp/vsock_vmtest_XXXX.pid
+declare -A PIDFILES
# virtme-ng offers a netdev for ssh when using "--ssh", but we also need a
# control port forwarded for vsock_test. Because virtme-ng doesn't support
@@ -33,12 +36,6 @@ readonly QEMU_PIDFILE=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
# add the kernel cmdline options that virtme-init uses to setup the interface.
readonly QEMU_TEST_PORT_FWD="hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}"
readonly QEMU_SSH_PORT_FWD="hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}"
-readonly QEMU_OPTS="\
- -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \
- -device virtio-net-pci,netdev=n0 \
- -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \
- --pidfile ${QEMU_PIDFILE} \
-"
readonly KERNEL_CMDLINE="\
virtme.dhcp net.ifnames=0 biosdevname=0 \
virtme.ssh virtme_ssh_channel=tcp virtme_ssh_user=$USER \
@@ -51,6 +48,8 @@ readonly TEST_DESCS=(
"Run vsock_test using the loopback transport in the VM."
)
+readonly USE_SHARED_VM=(vm_server_host_client vm_client_host_server vm_loopback)
+
VERBOSE=0
usage() {
@@ -84,21 +83,33 @@ die() {
exit "${KSFT_FAIL}"
}
+check_result() {
+ local rc arg
+
+ rc=$1
+ arg=$2
+
+ cnt_total=$(( cnt_total + 1 ))
+
+ if [[ ${rc} -eq ${KSFT_PASS} ]]; then
+ cnt_pass=$(( cnt_pass + 1 ))
+ echo "ok ${cnt_total} ${arg}"
+ elif [[ ${rc} -eq ${KSFT_SKIP} ]]; then
+ cnt_skip=$(( cnt_skip + 1 ))
+ echo "ok ${cnt_total} ${arg} # SKIP"
+ elif [[ ${rc} -eq ${KSFT_FAIL} ]]; then
+ cnt_fail=$(( cnt_fail + 1 ))
+ echo "not ok ${cnt_total} ${arg} # exit=${rc}"
+ fi
+}
+
vm_ssh() {
ssh -q -o UserKnownHostsFile=/dev/null -p ${SSH_HOST_PORT} localhost "$@"
return $?
}
cleanup() {
- if [[ -s "${QEMU_PIDFILE}" ]]; then
- pkill -SIGTERM -F "${QEMU_PIDFILE}" > /dev/null 2>&1
- fi
-
- # If failure occurred during or before qemu start up, then we need
- # to clean this up ourselves.
- if [[ -e "${QEMU_PIDFILE}" ]]; then
- rm "${QEMU_PIDFILE}"
- fi
+ terminate_pidfiles "${!PIDFILES[@]}"
}
check_args() {
@@ -147,7 +158,7 @@ check_vng() {
local version
local ok
- tested_versions=("1.33" "1.36")
+ tested_versions=("1.33" "1.36" "1.37")
version="$(vng --version)"
ok=0
@@ -188,10 +199,37 @@ handle_build() {
popd &>/dev/null
}
+create_pidfile() {
+ local pidfile
+
+ pidfile=$(mktemp "${PIDFILE_TEMPLATE}")
+ PIDFILES["${pidfile}"]=1
+
+ echo "${pidfile}"
+}
+
+terminate_pidfiles() {
+ local pidfile
+
+ for pidfile in "$@"; do
+ if [[ -s "${pidfile}" ]]; then
+ pkill -SIGTERM -F "${pidfile}" > /dev/null 2>&1
+ fi
+
+ if [[ -e "${pidfile}" ]]; then
+ rm -f "${pidfile}"
+ fi
+
+ unset "PIDFILES[${pidfile}]"
+ done
+}
+
vm_start() {
+ local pidfile=$1
local logfile=/dev/null
local verbose_opt=""
local kernel_opt=""
+ local qemu_opts=""
local qemu
qemu=$(command -v "${QEMU}")
@@ -201,6 +239,13 @@ vm_start() {
logfile=/dev/stdout
fi
+ qemu_opts="\
+ -netdev user,id=n0,${QEMU_TEST_PORT_FWD},${QEMU_SSH_PORT_FWD} \
+ -device virtio-net-pci,netdev=n0 \
+ -device vhost-vsock-pci,guest-cid=${VSOCK_CID} \
+ --pidfile ${pidfile}
+ "
+
if [[ "${BUILD}" -eq 1 ]]; then
kernel_opt="${KERNEL_CHECKOUT}"
fi
@@ -209,16 +254,14 @@ vm_start() {
--run \
${kernel_opt} \
${verbose_opt} \
- --qemu-opts="${QEMU_OPTS}" \
+ --qemu-opts="${qemu_opts}" \
--qemu="${qemu}" \
--user root \
--append "${KERNEL_CMDLINE}" \
--rw &> ${logfile} &
- if ! timeout ${WAIT_TOTAL} \
- bash -c 'while [[ ! -s '"${QEMU_PIDFILE}"' ]]; do sleep 1; done; exit 0'; then
- die "failed to boot VM"
- fi
+ timeout "${WAIT_QEMU}" \
+ bash -c 'while [[ ! -s '"${pidfile}"' ]]; do sleep 1; done; exit 0'
}
vm_wait_for_ssh() {
@@ -251,9 +294,11 @@ wait_for_listener()
# for tcp protocol additionally check the socket state
[ "${protocol}" = "tcp" ] && pattern="${pattern}0A"
+
for i in $(seq "${max_intervals}"); do
- if awk '{print $2" "$4}' /proc/net/"${protocol}"* | \
- grep -q "${pattern}"; then
+ if awk -v pattern="${pattern}" \
+ 'BEGIN {rc=1} $2" "$4 ~ pattern {rc=0} END {exit rc}' \
+ /proc/net/"${protocol}"*; then
break
fi
sleep "${interval}"
@@ -270,113 +315,196 @@ EOF
}
host_wait_for_listener() {
- wait_for_listener "${TEST_HOST_PORT_LISTENER}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}"
+ local port=$1
+
+ wait_for_listener "${port}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}"
}
-__log_stdin() {
- cat | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }'
+vm_vsock_test() {
+ local host=$1
+ local cid=$2
+ local port=$3
+ local rc
+
+ # log output and use pipefail to respect vsock_test errors
+ set -o pipefail
+ if [[ "${host}" != server ]]; then
+ vm_ssh -- "${VSOCK_TEST}" \
+ --mode=client \
+ --control-host="${host}" \
+ --peer-cid="${cid}" \
+ --control-port="${port}" \
+ 2>&1 | log_guest
+ rc=$?
+ else
+ vm_ssh -- "${VSOCK_TEST}" \
+ --mode=server \
+ --peer-cid="${cid}" \
+ --control-port="${port}" \
+ 2>&1 | log_guest &
+ rc=$?
+
+ if [[ $rc -ne 0 ]]; then
+ set +o pipefail
+ return $rc
+ fi
+
+ vm_wait_for_listener "${port}"
+ rc=$?
+ fi
+ set +o pipefail
+
+ return $rc
}
-__log_args() {
- echo "$*" | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }'
+host_vsock_test() {
+ local host=$1
+ local cid=$2
+ local port=$3
+ local rc
+
+ # log output and use pipefail to respect vsock_test errors
+ set -o pipefail
+ if [[ "${host}" != server ]]; then
+ ${VSOCK_TEST} \
+ --mode=client \
+ --peer-cid="${cid}" \
+ --control-host="${host}" \
+ --control-port="${port}" 2>&1 | log_host
+ rc=$?
+ else
+ ${VSOCK_TEST} \
+ --mode=server \
+ --peer-cid="${cid}" \
+ --control-port="${port}" 2>&1 | log_host &
+ rc=$?
+
+ if [[ $rc -ne 0 ]]; then
+ set +o pipefail
+ return $rc
+ fi
+
+ host_wait_for_listener "${port}"
+ rc=$?
+ fi
+ set +o pipefail
+
+ return $rc
}
log() {
- local prefix="$1"
+ local redirect
+ local prefix
- shift
- local redirect=
if [[ ${VERBOSE} -eq 0 ]]; then
redirect=/dev/null
else
redirect=/dev/stdout
fi
+ prefix="${LOG_PREFIX:-}"
+
if [[ "$#" -eq 0 ]]; then
- __log_stdin | tee -a "${LOG}" > ${redirect}
+ if [[ -n "${prefix}" ]]; then
+ awk -v prefix="${prefix}" '{printf "%s: %s\n", prefix, $0}'
+ else
+ cat
+ fi
else
- __log_args "$@" | tee -a "${LOG}" > ${redirect}
- fi
-}
-
-log_setup() {
- log "setup" "$@"
+ if [[ -n "${prefix}" ]]; then
+ echo "${prefix}: " "$@"
+ else
+ echo "$@"
+ fi
+ fi | tee -a "${LOG}" > "${redirect}"
}
log_host() {
- local testname=$1
-
- shift
- log "test:${testname}:host" "$@"
+ LOG_PREFIX=host log "$@"
}
log_guest() {
- local testname=$1
-
- shift
- log "test:${testname}:guest" "$@"
+ LOG_PREFIX=guest log "$@"
}
test_vm_server_host_client() {
- local testname="${FUNCNAME[0]#test_}"
+ if ! vm_vsock_test "server" 2 "${TEST_GUEST_PORT}"; then
+ return "${KSFT_FAIL}"
+ fi
- vm_ssh -- "${VSOCK_TEST}" \
- --mode=server \
- --control-port="${TEST_GUEST_PORT}" \
- --peer-cid=2 \
- 2>&1 | log_guest "${testname}" &
+ if ! host_vsock_test "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"; then
+ return "${KSFT_FAIL}"
+ fi
- vm_wait_for_listener "${TEST_GUEST_PORT}"
+ return "${KSFT_PASS}"
+}
- ${VSOCK_TEST} \
- --mode=client \
- --control-host=127.0.0.1 \
- --peer-cid="${VSOCK_CID}" \
- --control-port="${TEST_HOST_PORT}" 2>&1 | log_host "${testname}"
+test_vm_client_host_server() {
+ if ! host_vsock_test "server" "${VSOCK_CID}" "${TEST_HOST_PORT_LISTENER}"; then
+ return "${KSFT_FAIL}"
+ fi
- return $?
+ if ! vm_vsock_test "10.0.2.2" 2 "${TEST_HOST_PORT_LISTENER}"; then
+ return "${KSFT_FAIL}"
+ fi
+
+ return "${KSFT_PASS}"
}
-test_vm_client_host_server() {
- local testname="${FUNCNAME[0]#test_}"
+test_vm_loopback() {
+ local port=60000 # non-forwarded local port
- ${VSOCK_TEST} \
- --mode "server" \
- --control-port "${TEST_HOST_PORT_LISTENER}" \
- --peer-cid "${VSOCK_CID}" 2>&1 | log_host "${testname}" &
+ vm_ssh -- modprobe vsock_loopback &> /dev/null || :
- host_wait_for_listener
+ if ! vm_vsock_test "server" 1 "${port}"; then
+ return "${KSFT_FAIL}"
+ fi
- vm_ssh -- "${VSOCK_TEST}" \
- --mode=client \
- --control-host=10.0.2.2 \
- --peer-cid=2 \
- --control-port="${TEST_HOST_PORT_LISTENER}" 2>&1 | log_guest "${testname}"
+ if ! vm_vsock_test "127.0.0.1" 1 "${port}"; then
+ return "${KSFT_FAIL}"
+ fi
- return $?
+ return "${KSFT_PASS}"
}
-test_vm_loopback() {
- local testname="${FUNCNAME[0]#test_}"
- local port=60000 # non-forwarded local port
+shared_vm_test() {
+ local tname
+
+ tname="${1}"
+
+ for testname in "${USE_SHARED_VM[@]}"; do
+ if [[ "${tname}" == "${testname}" ]]; then
+ return 0
+ fi
+ done
- vm_ssh -- "${VSOCK_TEST}" \
- --mode=server \
- --control-port="${port}" \
- --peer-cid=1 2>&1 | log_guest "${testname}" &
+ return 1
+}
- vm_wait_for_listener "${port}"
+shared_vm_tests_requested() {
+ for arg in "$@"; do
+ if shared_vm_test "${arg}"; then
+ return 0
+ fi
+ done
- vm_ssh -- "${VSOCK_TEST}" \
- --mode=client \
- --control-host="127.0.0.1" \
- --control-port="${port}" \
- --peer-cid=1 2>&1 | log_guest "${testname}"
+ return 1
+}
- return $?
+run_shared_vm_tests() {
+ local arg
+
+ for arg in "$@"; do
+ if ! shared_vm_test "${arg}"; then
+ continue
+ fi
+
+ run_shared_vm_test "${arg}"
+ check_result "$?" "${arg}"
+ done
}
-run_test() {
+run_shared_vm_test() {
local host_oops_cnt_before
local host_warn_cnt_before
local vm_oops_cnt_before
@@ -399,31 +527,32 @@ run_test() {
host_oops_cnt_after=$(dmesg | grep -i 'Oops' | wc -l)
if [[ ${host_oops_cnt_after} -gt ${host_oops_cnt_before} ]]; then
- echo "FAIL: kernel oops detected on host" | log_host "${name}"
+ echo "FAIL: kernel oops detected on host" | log_host
rc=$KSFT_FAIL
fi
host_warn_cnt_after=$(dmesg --level=warn | grep -c -i 'vsock')
if [[ ${host_warn_cnt_after} -gt ${host_warn_cnt_before} ]]; then
- echo "FAIL: kernel warning detected on host" | log_host "${name}"
+ echo "FAIL: kernel warning detected on host" | log_host
rc=$KSFT_FAIL
fi
vm_oops_cnt_after=$(vm_ssh -- dmesg | grep -i 'Oops' | wc -l)
if [[ ${vm_oops_cnt_after} -gt ${vm_oops_cnt_before} ]]; then
- echo "FAIL: kernel oops detected on vm" | log_host "${name}"
+ echo "FAIL: kernel oops detected on vm" | log_host
rc=$KSFT_FAIL
fi
vm_warn_cnt_after=$(vm_ssh -- dmesg --level=warn | grep -c -i 'vsock')
if [[ ${vm_warn_cnt_after} -gt ${vm_warn_cnt_before} ]]; then
- echo "FAIL: kernel warning detected on vm" | log_host "${name}"
+ echo "FAIL: kernel warning detected on vm" | log_host
rc=$KSFT_FAIL
fi
return "${rc}"
}
+BUILD=0
QEMU="qemu-system-$(uname -m)"
while getopts :hvsq:b o
@@ -452,30 +581,21 @@ handle_build
echo "1..${#ARGS[@]}"
-log_setup "Booting up VM"
-vm_start
-vm_wait_for_ssh
-log_setup "VM booted up"
-
cnt_pass=0
cnt_fail=0
cnt_skip=0
cnt_total=0
-for arg in "${ARGS[@]}"; do
- run_test "${arg}"
- rc=$?
- if [[ ${rc} -eq $KSFT_PASS ]]; then
- cnt_pass=$(( cnt_pass + 1 ))
- echo "ok ${cnt_total} ${arg}"
- elif [[ ${rc} -eq $KSFT_SKIP ]]; then
- cnt_skip=$(( cnt_skip + 1 ))
- echo "ok ${cnt_total} ${arg} # SKIP"
- elif [[ ${rc} -eq $KSFT_FAIL ]]; then
- cnt_fail=$(( cnt_fail + 1 ))
- echo "not ok ${cnt_total} ${arg} # exit=$rc"
- fi
- cnt_total=$(( cnt_total + 1 ))
-done
+
+if shared_vm_tests_requested "${ARGS[@]}"; then
+ log_host "Booting up VM"
+ pidfile="$(create_pidfile)"
+ vm_start "${pidfile}"
+ vm_wait_for_ssh
+ log_host "VM booted up"
+
+ run_shared_vm_tests "${ARGS[@]}"
+ terminate_pidfiles "${pidfile}"
+fi
echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}"
echo "Log: ${LOG}"