diff mbox series

[net-next] selftests/vsock: add initial vmtest.sh for vsock

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

Commit Message

Bobby Eshleman April 11, 2025, 1:07 a.m. UTC
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,

Comments

Stefano Garzarella April 11, 2025, 8:32 a.m. UTC | #1
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>
>
Bobby Eshleman April 14, 2025, 5:12 p.m. UTC | #2
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 mbox series

Patch

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}