Message ID | 20250410-vsock-vmtest-v1-1-f35a81dab98c@gmail.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [net-next] selftests/vsock: add initial vmtest.sh for vsock | expand |
On Thu, Apr 10, 2025 at 06:07:59PM -0700, Bobby Eshleman wrote: >This commit introduces a new vmtest.sh runner for vsock. > >It uses virtme-ng/qemu to run tests in a VM. The tests are designed to >validate both G2H and H2G paths. The testing tools from tools from >tools/testing/vsock/ are reused. Currently, only vsock_test is used. Coool, thanks for that. I'll leave some comments, but I'll try this next week since today I'm a bit busy. > >Only tested on x86. > >To run: > > $ tools/testing/selftests/vsock/vmtest.sh > >Signed-off-by: Bobby Eshleman <bobbyeshleman@gmail.com> >--- > MAINTAINERS | 1 + > tools/testing/selftests/vsock/.gitignore | 1 + > tools/testing/selftests/vsock/config.vsock | 6 + > tools/testing/selftests/vsock/vmtest.sh | 247 +++++++++++++++++++++++++++++ > 4 files changed, 255 insertions(+) > >diff --git a/MAINTAINERS b/MAINTAINERS >index c3fce441672349f7850c57d788bc1a29b203fba5..f214cf7c4fb59ec67885ee6c81daa44e17c80f5f 100644 >--- a/MAINTAINERS >+++ b/MAINTAINERS >@@ -25323,6 +25323,7 @@ F: include/uapi/linux/vm_sockets.h > F: include/uapi/linux/vm_sockets_diag.h > F: include/uapi/linux/vsockmon.h > F: net/vmw_vsock/ >+F: tools/testing/selftests/vsock/ > F: tools/testing/vsock/ > > VMALLOC >diff --git a/tools/testing/selftests/vsock/.gitignore b/tools/testing/selftests/vsock/.gitignore >new file mode 100644 >index 0000000000000000000000000000000000000000..1950aa8ac68c0831c12c1aaa429da45bbe41e60f >--- /dev/null >+++ b/tools/testing/selftests/vsock/.gitignore >@@ -0,0 +1 @@ >+vsock_selftests.log >diff --git a/tools/testing/selftests/vsock/config.vsock b/tools/testing/selftests/vsock/config.vsock >new file mode 100644 >index 0000000000000000000000000000000000000000..a229c329d44e4a0b650d073b74949b577da3dc64 >--- /dev/null >+++ b/tools/testing/selftests/vsock/config.vsock >@@ -0,0 +1,6 @@ >+CONFIG_VSOCKETS=y >+CONFIG_VSOCKETS_DIAG=y >+CONFIG_VSOCKETS_LOOPBACK=y >+CONFIG_VIRTIO_VSOCKETS=y >+CONFIG_VIRTIO_VSOCKETS_COMMON=y >+CONFIG_VHOST_VSOCK=y Should we enabled also other transports? (I'm not sure since we don't test it) >diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh >new file mode 100755 >index 0000000000000000000000000000000000000000..f2dafcb893232f95ebb22104a62ce1e0312f4e89 >--- /dev/null >+++ b/tools/testing/selftests/vsock/vmtest.sh >@@ -0,0 +1,247 @@ >+#!/bin/bash >+# SPDX-License-Identifier: GPL-2.0 >+# >+# Copyright (c) 2025 Meta Platforms, Inc. and affiliates >+# >+# Dependencies: >+# * virtme-ng >+# * busybox-static (used by virtme-ng) >+# * qemu (used by virtme-ng) >+ >+SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" >+KERNEL_CHECKOUT=$(realpath ${SCRIPT_DIR}/../../../..) >+PLATFORM=${PLATFORM:-$(uname -m)} >+ >+if [[ -z "${QEMU:-}" ]]; then >+ QEMU=$(which qemu-system-${PLATFORM}) >+fi >+ >+VSOCK_TEST=${KERNEL_CHECKOUT}/tools/testing/vsock/vsock_test >+ >+TEST_GUEST_PORT=51000 >+TEST_HOST_PORT=50000 >+TEST_HOST_PORT_LISTENER=50001 >+SSH_GUEST_PORT=22 >+SSH_HOST_PORT=2222 >+VSOCK_CID=1234 >+ >+QEMU_PIDFILE=/tmp/qemu.pid >+ >+# 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 >+# adding an additional port to forward to the device created from "--ssh" and >+# virtme-init mistakenly sets identical IPs to the ssh device and additional >+# devices, we instead opt out of using --ssh, add the device manually, and also >+# add the kernel cmdline options that virtme-init uses to setup the interface. >+QEMU_OPTS="" >+QEMU_OPTS="${QEMU_OPTS} -netdev user,id=n0,hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}" >+QEMU_OPTS="${QEMU_OPTS},hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}" >+QEMU_OPTS="${QEMU_OPTS} -device virtio-net-pci,netdev=n0" >+QEMU_OPTS="${QEMU_OPTS} -device vhost-vsock-pci,guest-cid=${VSOCK_CID}" >+QEMU_OPTS="${QEMU_OPTS} --pidfile ${QEMU_PIDFILE}" >+KERNEL_CMDLINE="virtme.dhcp net.ifnames=0 biosdevname=0 virtme.ssh virtme_ssh_user=$USER" >+ >+LOG=${SCRIPT_DIR}/vsock_selftests.log >+ >+# Name Description >+tests=" >+ vm_server_host_client Run vsock_test in server mode on the VM and in client mode on the host. >+ vm_client_host_server Run vsock_test in client mode on the VM and in server mode on the host. What about adding tests also with loopback in the VM? >+" >+ >+usage() { >+ echo >+ echo "$0 [OPTIONS]" >+ echo >+ echo "Options" >+ echo " -v: verbose output" >+ echo >+ echo "Available tests${tests}" >+ exit 1 >+} >+ >+die() { >+ echo "$*" >&2 >+ exit 1 >+} >+ >+vm_ssh() { >+ ssh -q -o UserKnownHostsFile=/dev/null -p 2222 localhost $* >+ return $? >+} >+ >+cleanup() { >+ if [[ -f "${QEMU_PIDFILE}" ]]; then >+ pkill -9 -F ${QEMU_PIDFILE} 2>&1 >/dev/null >+ fi >+} >+ >+build() { >+ log_setup "Building kernel and tests" >+ >+ pushd ${KERNEL_CHECKOUT} >/dev/null >+ vng \ >+ --kconfig \ >+ --config ${KERNEL_CHECKOUT}/tools/testing/selftests/vsock/config.vsock >+ make -j$(nproc) >+ make -C ${KERNEL_CHECKOUT}/tools/testing/vsock >+ popd >/dev/null >+ echo >+} >+ >+vm_setup() { >+ local VNG_OPTS="" >+ if [[ "${VERBOSE}" = 1 ]]; then >+ VNG_OPTS="--verbose" >+ fi >+ vng \ >+ $VNG_OPTS \ >+ --run ~/local/linux \ >+ --qemu /bin/qemu-system-x86_64 \ >+ --qemu-opts="${QEMU_OPTS}" \ >+ --user root \ >+ --append "${KERNEL_CMDLINE}" \ >+ --rw 2>&1 >/dev/null & >+} >+ >+vm_wait_for_ssh() { >+ i=0 >+ while [[ true ]]; do >+ if (( i > 20 )); then >+ die "Timed out waiting for guest ssh" >+ fi >+ vm_ssh -- true >+ if [[ $? -eq 0 ]]; then >+ break >+ fi >+ i=$(( i + 1 )) >+ sleep 5 >+ done >+} >+ >+wait_for_listener() { >+ local PORT=$1 >+ local i=0 >+ while ! ss -ltn | grep -q ":${PORT}"; do >+ if (( i > 30 )); then >+ die "Timed out waiting for listener on port ${PORT}" >+ fi >+ sleep 3 >+ i=$(( i + 1 )) >+ done >+} >+ >+vm_wait_for_listener() { >+ vm_ssh -- "$(declare -f wait)for_listener); wait_for_listener >${TEST_GUEST_PORT}" >+} >+ >+host_wait_for_listener() { >+ wait_for_listener ${TEST_HOST_LISTENER_PORT} >+} >+ >+log() { >+ local prefix="$1" >+ shift >+ >+ if [[ "$#" -eq 0 ]]; then >+ cat | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} >+ else >+ echo "$*" | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} >+ fi >+} >+ >+log_setup() { >+ log "setup" "$@" >+} >+ >+log_host() { >+ testname=$1 >+ shift >+ log "test:${testname}:host" "$@" >+} >+ >+log_guest() { >+ testname=$1 >+ shift >+ log "test:${testname}:guest" "$@" >+} >+ >+test_vm_server_host_client() { >+ local testname="vm_server_host_client" >+ vm_ssh -- "${VSOCK_TEST}" \ >+ --mode=server \ >+ --control-port="${TEST_GUEST_PORT}" \ >+ --peer-cid=2 \ >+ 2>&1 | log_guest "${testname}" & Strange indentation here. >+ >+ vm_wait_for_listener >+ ${VSOCK_TEST} \ >+ --mode=client \ >+ --control-host=127.0.0.1 \ >+ --peer-cid="${VSOCK_CID}" \ >+ --control-port="${TEST_HOST_PORT}" 2>&1 | log_host "${testname}" >+ >+ rc=$? >+} >+ >+test_vm_client_host_server() { >+ local testname="vm_client_host_server" >+ >+ ${VSOCK_TEST} \ >+ --mode "server" \ >+ --control-port "${TEST_HOST_PORT_LISTENER}" \ >+ --peer-cid "${VSOCK_CID}" 2>&1 | log_host "${testname}" & >+ >+ host_wait_for_listener >+ >+ 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}" >+ >+ rc=$? >+} >+ >+run_test() { >+ unset IFS >+ name=$(echo "${1}" | awk '{ print $1 }') >+ eval test_"${name}" >+} >+ >+while getopts :hv o >+do >+ case $o in >+ v) VERBOSE=1;; >+ h|*) usage;; >+ esac >+done >+shift $((OPTIND-1)) >+ >+trap cleanup EXIT >+ >+> ${LOG} >+build >+log_setup "Booting up VM" >+vm_setup >+vm_wait_for_ssh >+log_setup "VM booted up" >+ >+IFS=" >+" >+cnt=0 >+for t in ${tests}; do >+ rc=0 >+ run_test "${t}" >+ if [[ ${rc} != 0 ]]; then >+ cnt=$(( cnt + 1 )) >+ fi >+done >+ >+if [[ ${cnt} = 0 ]]; then >+ echo OK In my suite I also check if we have some kernel warnings or oops. Should we add something similar or does the infrastructure already handle that? Thanks, Stefano >+else >+ echo FAILED: ${cnt} >+fi >+echo "Log: ${LOG}" >+exit ${cnt} > >--- >base-commit: cc04ed502457412960d215b9cd55f0d966fda255 >change-id: 20250325-vsock-vmtest-b3a21d2102c2 > >Best regards, >-- >Bobby Eshleman <bobbyeshleman@gmail.com> >
On Fri, Apr 11, 2025 at 10:32:45AM +0200, Stefano Garzarella wrote: > On Thu, Apr 10, 2025 at 06:07:59PM -0700, Bobby Eshleman wrote: > > This commit introduces a new vmtest.sh runner for vsock. > > > > It uses virtme-ng/qemu to run tests in a VM. The tests are designed to > > validate both G2H and H2G paths. The testing tools from tools from > > tools/testing/vsock/ are reused. Currently, only vsock_test is used. > > Coool, thanks for that. > I'll leave some comments, but I'll try this next week since today I'm a bit > busy. > > > > > Only tested on x86. > > > > To run: > > > > $ tools/testing/selftests/vsock/vmtest.sh > > > > Signed-off-by: Bobby Eshleman <bobbyeshleman@gmail.com> > > --- > > MAINTAINERS | 1 + > > tools/testing/selftests/vsock/.gitignore | 1 + > > tools/testing/selftests/vsock/config.vsock | 6 + > > tools/testing/selftests/vsock/vmtest.sh | 247 +++++++++++++++++++++++++++++ > > 4 files changed, 255 insertions(+) > > > > diff --git a/MAINTAINERS b/MAINTAINERS > > index c3fce441672349f7850c57d788bc1a29b203fba5..f214cf7c4fb59ec67885ee6c81daa44e17c80f5f 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -25323,6 +25323,7 @@ F: include/uapi/linux/vm_sockets.h > > F: include/uapi/linux/vm_sockets_diag.h > > F: include/uapi/linux/vsockmon.h > > F: net/vmw_vsock/ > > +F: tools/testing/selftests/vsock/ > > F: tools/testing/vsock/ > > > > VMALLOC > > diff --git a/tools/testing/selftests/vsock/.gitignore b/tools/testing/selftests/vsock/.gitignore > > new file mode 100644 > > index 0000000000000000000000000000000000000000..1950aa8ac68c0831c12c1aaa429da45bbe41e60f > > --- /dev/null > > +++ b/tools/testing/selftests/vsock/.gitignore > > @@ -0,0 +1 @@ > > +vsock_selftests.log > > diff --git a/tools/testing/selftests/vsock/config.vsock b/tools/testing/selftests/vsock/config.vsock > > new file mode 100644 > > index 0000000000000000000000000000000000000000..a229c329d44e4a0b650d073b74949b577da3dc64 > > --- /dev/null > > +++ b/tools/testing/selftests/vsock/config.vsock > > @@ -0,0 +1,6 @@ > > +CONFIG_VSOCKETS=y > > +CONFIG_VSOCKETS_DIAG=y > > +CONFIG_VSOCKETS_LOOPBACK=y > > +CONFIG_VIRTIO_VSOCKETS=y > > +CONFIG_VIRTIO_VSOCKETS_COMMON=y > > +CONFIG_VHOST_VSOCK=y > > Should we enabled also other transports? > > (I'm not sure since we don't test it) > Probably for the best to catch things that break the build? > > diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh > > new file mode 100755 > > index 0000000000000000000000000000000000000000..f2dafcb893232f95ebb22104a62ce1e0312f4e89 > > --- /dev/null > > +++ b/tools/testing/selftests/vsock/vmtest.sh > > @@ -0,0 +1,247 @@ > > +#!/bin/bash > > +# SPDX-License-Identifier: GPL-2.0 > > +# > > +# Copyright (c) 2025 Meta Platforms, Inc. and affiliates > > +# > > +# Dependencies: > > +# * virtme-ng > > +# * busybox-static (used by virtme-ng) > > +# * qemu (used by virtme-ng) > > + > > +SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" > > +KERNEL_CHECKOUT=$(realpath ${SCRIPT_DIR}/../../../..) > > +PLATFORM=${PLATFORM:-$(uname -m)} > > + > > +if [[ -z "${QEMU:-}" ]]; then > > + QEMU=$(which qemu-system-${PLATFORM}) > > +fi > > + > > +VSOCK_TEST=${KERNEL_CHECKOUT}/tools/testing/vsock/vsock_test > > + > > +TEST_GUEST_PORT=51000 > > +TEST_HOST_PORT=50000 > > +TEST_HOST_PORT_LISTENER=50001 > > +SSH_GUEST_PORT=22 > > +SSH_HOST_PORT=2222 > > +VSOCK_CID=1234 > > + > > +QEMU_PIDFILE=/tmp/qemu.pid > > + > > +# 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 > > +# adding an additional port to forward to the device created from "--ssh" and > > +# virtme-init mistakenly sets identical IPs to the ssh device and additional > > +# devices, we instead opt out of using --ssh, add the device manually, and also > > +# add the kernel cmdline options that virtme-init uses to setup the interface. > > +QEMU_OPTS="" > > +QEMU_OPTS="${QEMU_OPTS} -netdev user,id=n0,hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}" > > +QEMU_OPTS="${QEMU_OPTS},hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}" > > +QEMU_OPTS="${QEMU_OPTS} -device virtio-net-pci,netdev=n0" > > +QEMU_OPTS="${QEMU_OPTS} -device vhost-vsock-pci,guest-cid=${VSOCK_CID}" > > +QEMU_OPTS="${QEMU_OPTS} --pidfile ${QEMU_PIDFILE}" > > +KERNEL_CMDLINE="virtme.dhcp net.ifnames=0 biosdevname=0 virtme.ssh virtme_ssh_user=$USER" > > + > > +LOG=${SCRIPT_DIR}/vsock_selftests.log > > + > > +# Name Description > > +tests=" > > + vm_server_host_client Run vsock_test in server mode on the VM and in client mode on the host. > > + vm_client_host_server Run vsock_test in client mode on the VM and in server mode on the host. > > What about adding tests also with loopback in the VM? > Can do! > > +" > > + > > +usage() { > > + echo > > + echo "$0 [OPTIONS]" > > + echo > > + echo "Options" > > + echo " -v: verbose output" > > + echo > > + echo "Available tests${tests}" > > + exit 1 > > +} > > + > > +die() { > > + echo "$*" >&2 > > + exit 1 > > +} > > + > > +vm_ssh() { > > + ssh -q -o UserKnownHostsFile=/dev/null -p 2222 localhost $* > > + return $? > > +} > > + > > +cleanup() { > > + if [[ -f "${QEMU_PIDFILE}" ]]; then > > + pkill -9 -F ${QEMU_PIDFILE} 2>&1 >/dev/null > > + fi > > +} > > + > > +build() { > > + log_setup "Building kernel and tests" > > + > > + pushd ${KERNEL_CHECKOUT} >/dev/null > > + vng \ > > + --kconfig \ > > + --config ${KERNEL_CHECKOUT}/tools/testing/selftests/vsock/config.vsock > > + make -j$(nproc) > > + make -C ${KERNEL_CHECKOUT}/tools/testing/vsock > > + popd >/dev/null > > + echo > > +} > > + > > +vm_setup() { > > + local VNG_OPTS="" > > + if [[ "${VERBOSE}" = 1 ]]; then > > + VNG_OPTS="--verbose" > > + fi > > + vng \ > > + $VNG_OPTS \ > > + --run ~/local/linux \ > > + --qemu /bin/qemu-system-x86_64 \ > > + --qemu-opts="${QEMU_OPTS}" \ > > + --user root \ > > + --append "${KERNEL_CMDLINE}" \ > > + --rw 2>&1 >/dev/null & > > +} > > + > > +vm_wait_for_ssh() { > > + i=0 > > + while [[ true ]]; do > > + if (( i > 20 )); then > > + die "Timed out waiting for guest ssh" > > + fi > > + vm_ssh -- true > > + if [[ $? -eq 0 ]]; then > > + break > > + fi > > + i=$(( i + 1 )) > > + sleep 5 > > + done > > +} > > + > > +wait_for_listener() { > > + local PORT=$1 > > + local i=0 > > + while ! ss -ltn | grep -q ":${PORT}"; do > > + if (( i > 30 )); then > > + die "Timed out waiting for listener on port ${PORT}" > > + fi > > + sleep 3 > > + i=$(( i + 1 )) > > + done > > +} > > + > > +vm_wait_for_listener() { > > + vm_ssh -- "$(declare -f wait)for_listener); wait_for_listener > > ${TEST_GUEST_PORT}" > > +} > > + > > +host_wait_for_listener() { > > + wait_for_listener ${TEST_HOST_LISTENER_PORT} > > +} > > + > > +log() { > > + local prefix="$1" > > + shift > > + > > + if [[ "$#" -eq 0 ]]; then > > + cat | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} > > + else > > + echo "$*" | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} > > + fi > > +} > > + > > +log_setup() { > > + log "setup" "$@" > > +} > > + > > +log_host() { > > + testname=$1 > > + shift > > + log "test:${testname}:host" "$@" > > +} > > + > > +log_guest() { > > + testname=$1 > > + shift > > + log "test:${testname}:guest" "$@" > > +} > > + > > +test_vm_server_host_client() { > > + local testname="vm_server_host_client" > > + vm_ssh -- "${VSOCK_TEST}" \ > > + --mode=server \ > > + --control-port="${TEST_GUEST_PORT}" \ > > + --peer-cid=2 \ > > + 2>&1 | log_guest "${testname}" & > > Strange indentation here. > Got it. > > + > > + vm_wait_for_listener > > + ${VSOCK_TEST} \ > > + --mode=client \ > > + --control-host=127.0.0.1 \ > > + --peer-cid="${VSOCK_CID}" \ > > + --control-port="${TEST_HOST_PORT}" 2>&1 | log_host "${testname}" > > + > > + rc=$? > > +} > > + > > +test_vm_client_host_server() { > > + local testname="vm_client_host_server" > > + > > + ${VSOCK_TEST} \ > > + --mode "server" \ > > + --control-port "${TEST_HOST_PORT_LISTENER}" \ > > + --peer-cid "${VSOCK_CID}" 2>&1 | log_host "${testname}" & > > + > > + host_wait_for_listener > > + > > + 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}" > > + > > + rc=$? > > +} > > + > > +run_test() { > > + unset IFS > > + name=$(echo "${1}" | awk '{ print $1 }') > > + eval test_"${name}" > > +} > > + > > +while getopts :hv o > > +do > > + case $o in > > + v) VERBOSE=1;; > > + h|*) usage;; > > + esac > > +done > > +shift $((OPTIND-1)) > > + > > +trap cleanup EXIT > > + > > +> ${LOG} > > +build > > +log_setup "Booting up VM" > > +vm_setup > > +vm_wait_for_ssh > > +log_setup "VM booted up" > > + > > +IFS=" > > +" > > +cnt=0 > > +for t in ${tests}; do > > + rc=0 > > + run_test "${t}" > > + if [[ ${rc} != 0 ]]; then > > + cnt=$(( cnt + 1 )) > > + fi > > +done > > + > > +if [[ ${cnt} = 0 ]]; then > > + echo OK > > In my suite I also check if we have some kernel warnings or oops. > Should we add something similar or does the infrastructure already > handle that? > I think we'll need to add that, AFAIK infra like NIPA depends entirely on the exit code of the test script. BTW, I'm planning on integrating with NIPA, but that is still TODO. > Thanks, > Stefano > Thanks! -Bobby
diff --git a/MAINTAINERS b/MAINTAINERS index c3fce441672349f7850c57d788bc1a29b203fba5..f214cf7c4fb59ec67885ee6c81daa44e17c80f5f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -25323,6 +25323,7 @@ F: include/uapi/linux/vm_sockets.h F: include/uapi/linux/vm_sockets_diag.h F: include/uapi/linux/vsockmon.h F: net/vmw_vsock/ +F: tools/testing/selftests/vsock/ F: tools/testing/vsock/ VMALLOC diff --git a/tools/testing/selftests/vsock/.gitignore b/tools/testing/selftests/vsock/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..1950aa8ac68c0831c12c1aaa429da45bbe41e60f --- /dev/null +++ b/tools/testing/selftests/vsock/.gitignore @@ -0,0 +1 @@ +vsock_selftests.log diff --git a/tools/testing/selftests/vsock/config.vsock b/tools/testing/selftests/vsock/config.vsock new file mode 100644 index 0000000000000000000000000000000000000000..a229c329d44e4a0b650d073b74949b577da3dc64 --- /dev/null +++ b/tools/testing/selftests/vsock/config.vsock @@ -0,0 +1,6 @@ +CONFIG_VSOCKETS=y +CONFIG_VSOCKETS_DIAG=y +CONFIG_VSOCKETS_LOOPBACK=y +CONFIG_VIRTIO_VSOCKETS=y +CONFIG_VIRTIO_VSOCKETS_COMMON=y +CONFIG_VHOST_VSOCK=y diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh new file mode 100755 index 0000000000000000000000000000000000000000..f2dafcb893232f95ebb22104a62ce1e0312f4e89 --- /dev/null +++ b/tools/testing/selftests/vsock/vmtest.sh @@ -0,0 +1,247 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2025 Meta Platforms, Inc. and affiliates +# +# Dependencies: +# * virtme-ng +# * busybox-static (used by virtme-ng) +# * qemu (used by virtme-ng) + +SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" +KERNEL_CHECKOUT=$(realpath ${SCRIPT_DIR}/../../../..) +PLATFORM=${PLATFORM:-$(uname -m)} + +if [[ -z "${QEMU:-}" ]]; then + QEMU=$(which qemu-system-${PLATFORM}) +fi + +VSOCK_TEST=${KERNEL_CHECKOUT}/tools/testing/vsock/vsock_test + +TEST_GUEST_PORT=51000 +TEST_HOST_PORT=50000 +TEST_HOST_PORT_LISTENER=50001 +SSH_GUEST_PORT=22 +SSH_HOST_PORT=2222 +VSOCK_CID=1234 + +QEMU_PIDFILE=/tmp/qemu.pid + +# 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 +# adding an additional port to forward to the device created from "--ssh" and +# virtme-init mistakenly sets identical IPs to the ssh device and additional +# devices, we instead opt out of using --ssh, add the device manually, and also +# add the kernel cmdline options that virtme-init uses to setup the interface. +QEMU_OPTS="" +QEMU_OPTS="${QEMU_OPTS} -netdev user,id=n0,hostfwd=tcp::${TEST_HOST_PORT}-:${TEST_GUEST_PORT}" +QEMU_OPTS="${QEMU_OPTS},hostfwd=tcp::${SSH_HOST_PORT}-:${SSH_GUEST_PORT}" +QEMU_OPTS="${QEMU_OPTS} -device virtio-net-pci,netdev=n0" +QEMU_OPTS="${QEMU_OPTS} -device vhost-vsock-pci,guest-cid=${VSOCK_CID}" +QEMU_OPTS="${QEMU_OPTS} --pidfile ${QEMU_PIDFILE}" +KERNEL_CMDLINE="virtme.dhcp net.ifnames=0 biosdevname=0 virtme.ssh virtme_ssh_user=$USER" + +LOG=${SCRIPT_DIR}/vsock_selftests.log + +# Name Description +tests=" + vm_server_host_client Run vsock_test in server mode on the VM and in client mode on the host. + vm_client_host_server Run vsock_test in client mode on the VM and in server mode on the host. +" + +usage() { + echo + echo "$0 [OPTIONS]" + echo + echo "Options" + echo " -v: verbose output" + echo + echo "Available tests${tests}" + exit 1 +} + +die() { + echo "$*" >&2 + exit 1 +} + +vm_ssh() { + ssh -q -o UserKnownHostsFile=/dev/null -p 2222 localhost $* + return $? +} + +cleanup() { + if [[ -f "${QEMU_PIDFILE}" ]]; then + pkill -9 -F ${QEMU_PIDFILE} 2>&1 >/dev/null + fi +} + +build() { + log_setup "Building kernel and tests" + + pushd ${KERNEL_CHECKOUT} >/dev/null + vng \ + --kconfig \ + --config ${KERNEL_CHECKOUT}/tools/testing/selftests/vsock/config.vsock + make -j$(nproc) + make -C ${KERNEL_CHECKOUT}/tools/testing/vsock + popd >/dev/null + echo +} + +vm_setup() { + local VNG_OPTS="" + if [[ "${VERBOSE}" = 1 ]]; then + VNG_OPTS="--verbose" + fi + vng \ + $VNG_OPTS \ + --run ~/local/linux \ + --qemu /bin/qemu-system-x86_64 \ + --qemu-opts="${QEMU_OPTS}" \ + --user root \ + --append "${KERNEL_CMDLINE}" \ + --rw 2>&1 >/dev/null & +} + +vm_wait_for_ssh() { + i=0 + while [[ true ]]; do + if (( i > 20 )); then + die "Timed out waiting for guest ssh" + fi + vm_ssh -- true + if [[ $? -eq 0 ]]; then + break + fi + i=$(( i + 1 )) + sleep 5 + done +} + +wait_for_listener() { + local PORT=$1 + local i=0 + while ! ss -ltn | grep -q ":${PORT}"; do + if (( i > 30 )); then + die "Timed out waiting for listener on port ${PORT}" + fi + sleep 3 + i=$(( i + 1 )) + done +} + +vm_wait_for_listener() { + vm_ssh -- "$(declare -f wait_for_listener); wait_for_listener ${TEST_GUEST_PORT}" +} + +host_wait_for_listener() { + wait_for_listener ${TEST_HOST_LISTENER_PORT} +} + +log() { + local prefix="$1" + shift + + if [[ "$#" -eq 0 ]]; then + cat | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} + else + echo "$*" | awk '{ printf "%s:\t%s\n","'"${prefix}"'", $0 }' | tee -a ${LOG} + fi +} + +log_setup() { + log "setup" "$@" +} + +log_host() { + testname=$1 + shift + log "test:${testname}:host" "$@" +} + +log_guest() { + testname=$1 + shift + log "test:${testname}:guest" "$@" +} + +test_vm_server_host_client() { + local testname="vm_server_host_client" + vm_ssh -- "${VSOCK_TEST}" \ + --mode=server \ + --control-port="${TEST_GUEST_PORT}" \ + --peer-cid=2 \ + 2>&1 | log_guest "${testname}" & + + vm_wait_for_listener + ${VSOCK_TEST} \ + --mode=client \ + --control-host=127.0.0.1 \ + --peer-cid="${VSOCK_CID}" \ + --control-port="${TEST_HOST_PORT}" 2>&1 | log_host "${testname}" + + rc=$? +} + +test_vm_client_host_server() { + local testname="vm_client_host_server" + + ${VSOCK_TEST} \ + --mode "server" \ + --control-port "${TEST_HOST_PORT_LISTENER}" \ + --peer-cid "${VSOCK_CID}" 2>&1 | log_host "${testname}" & + + host_wait_for_listener + + 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}" + + rc=$? +} + +run_test() { + unset IFS + name=$(echo "${1}" | awk '{ print $1 }') + eval test_"${name}" +} + +while getopts :hv o +do + case $o in + v) VERBOSE=1;; + h|*) usage;; + esac +done +shift $((OPTIND-1)) + +trap cleanup EXIT + +> ${LOG} +build +log_setup "Booting up VM" +vm_setup +vm_wait_for_ssh +log_setup "VM booted up" + +IFS=" +" +cnt=0 +for t in ${tests}; do + rc=0 + run_test "${t}" + if [[ ${rc} != 0 ]]; then + cnt=$(( cnt + 1 )) + fi +done + +if [[ ${cnt} = 0 ]]; then + echo OK +else + echo FAILED: ${cnt} +fi +echo "Log: ${LOG}" +exit ${cnt}
This commit introduces a new vmtest.sh runner for vsock. It uses virtme-ng/qemu to run tests in a VM. The tests are designed to validate both G2H and H2G paths. The testing tools from tools from tools/testing/vsock/ are reused. Currently, only vsock_test is used. Only tested on x86. To run: $ tools/testing/selftests/vsock/vmtest.sh Signed-off-by: Bobby Eshleman <bobbyeshleman@gmail.com> --- MAINTAINERS | 1 + tools/testing/selftests/vsock/.gitignore | 1 + tools/testing/selftests/vsock/config.vsock | 6 + tools/testing/selftests/vsock/vmtest.sh | 247 +++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+) --- base-commit: cc04ed502457412960d215b9cd55f0d966fda255 change-id: 20250325-vsock-vmtest-b3a21d2102c2 Best regards,