[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <phckm6qx2drazblg4fsheqe4meg7likmvhbyquffwct4xj35ub@ddz2iikovcq5>
Date: Tue, 2 Sep 2025 17:40:38 +0200
From: Stefano Garzarella <sgarzare@...hat.com>
To: Bobby Eshleman <bobbyeshleman@...il.com>
Cc: Shuah Khan <shuah@...nel.org>, "David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>, Simon Horman <horms@...nel.org>,
Stefan Hajnoczi <stefanha@...hat.com>, "Michael S. Tsirkin" <mst@...hat.com>,
Jason Wang <jasowang@...hat.com>, Xuan Zhuo <xuanzhuo@...ux.alibaba.com>,
Eugenio Pérez <eperezma@...hat.com>, "K. Y. Srinivasan" <kys@...rosoft.com>,
Haiyang Zhang <haiyangz@...rosoft.com>, Wei Liu <wei.liu@...nel.org>, Dexuan Cui <decui@...rosoft.com>,
Bryan Tan <bryan-bt.tan@...adcom.com>, Vishnu Dasa <vishnu.dasa@...adcom.com>,
Broadcom internal kernel review list <bcm-kernel-feedback-list@...adcom.com>, virtualization@...ts.linux.dev, netdev@...r.kernel.org,
linux-kselftest@...r.kernel.org, linux-kernel@...r.kernel.org, kvm@...r.kernel.org,
linux-hyperv@...r.kernel.org, berrange@...hat.com, Bobby Eshleman <bobbyeshleman@...a.com>
Subject: Re: [PATCH net-next v5 9/9] selftests/vsock: add namespace tests
On Wed, Aug 27, 2025 at 05:31:37PM -0700, Bobby Eshleman wrote:
>From: Bobby Eshleman <bobbyeshleman@...a.com>
>
>Add tests for namespace support in vsock. Use socat for basic connection
Are netns tests skipped if the kernel doesn't support it?
Thanks,
Stefano
>failure tests and vsock_test for full functionality tests when
>communication is expected to succeed. vsock_test is not used for failure
>cases because in theory vsock_test could allow connection and some
>traffic flow but fail on some other case (e.g., fail on MSG_ZEROCOPY).
>
>Tests cover all cases of clients and servers being in all variants of
>local ns, global ns, host process, and VM process.
>
>Legacy tests are retained and executed in the init ns.
>
>Signed-off-by: Bobby Eshleman <bobbyeshleman@...a.com>
>
>---
>Changes in v5:
>- use /proc/sys/net/vsock/ns_mode
>- clarify logic of tests that reuse the same VM and tests that require
> netns setup
>- fix unassigned BUILD bug
>---
> tools/testing/selftests/vsock/vmtest.sh | 913 ++++++++++++++++++++++++++++----
> 1 file changed, 808 insertions(+), 105 deletions(-)
>
>diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh
>index 5e36d1068f6f..9d830eb7e829 100755
>--- a/tools/testing/selftests/vsock/vmtest.sh
>+++ b/tools/testing/selftests/vsock/vmtest.sh
>@@ -7,6 +7,7 @@
> # * virtme-ng
> # * busybox-static (used by virtme-ng)
> # * qemu (used by virtme-ng)
>+# * socat
>
> readonly SCRIPT_DIR="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
> readonly KERNEL_CHECKOUT=$(realpath "${SCRIPT_DIR}"/../../../../)
>@@ -23,7 +24,7 @@ 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
>
> # 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,23 +34,125 @@ 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 \
> "
> readonly LOG=$(mktemp /tmp/vsock_vmtest_XXXX.log)
>-readonly TEST_NAMES=(vm_server_host_client vm_client_host_server vm_loopback)
>+readonly TEST_NAMES=(
>+ vm_server_host_client
>+ vm_client_host_server
>+ vm_loopback
>+ host_vsock_ns_mode_ok
>+ host_vsock_ns_mode_write_once_ok
>+ global_same_cid_fails
>+ local_same_cid_ok
>+ global_local_same_cid_ok
>+ local_global_same_cid_ok
>+ diff_ns_global_host_connect_to_global_vm_ok
>+ diff_ns_global_host_connect_to_local_vm_fails
>+ diff_ns_global_vm_connect_to_global_host_ok
>+ diff_ns_global_vm_connect_to_local_host_fails
>+ diff_ns_local_host_connect_to_local_vm_fails
>+ diff_ns_local_vm_connect_to_local_host_fails
>+ diff_ns_global_to_local_loopback_local_fails
>+ diff_ns_local_to_global_loopback_fails
>+ diff_ns_local_to_local_loopback_fails
>+ diff_ns_global_to_global_loopback_ok
>+ same_ns_local_loopback_ok
>+ same_ns_local_host_connect_to_local_vm_ok
>+ same_ns_local_vm_connect_to_local_host_ok
>+)
>+
> readonly TEST_DESCS=(
>+ # 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."
>+
>+ # vm_loopback
> "Run vsock_test using the loopback transport in the VM."
>+
>+ # host_vsock_ns_mode_ok
>+ "Check /proc/sys/net/vsock/ns_mode strings on the host."
>+
>+ # host_vsock_ns_mode_write_once_ok
>+ "Check /proc/sys/net/vsock/ns_mode is write-once on the host."
>+
>+ # global_same_cid_fails
>+ "Check QEMU fails to start two VMs with same CID in two different global namespaces."
>+
>+ # local_same_cid_ok
>+ "Check QEMU successfully starts two VMs with same CID in two different local namespaces."
>+
>+ # global_local_same_cid_ok
>+ "Check QEMU successfully starts one VM in a global ns and then another VM in a local ns with the same CID."
>+
>+ # local_global_same_cid_ok
>+ "Check QEMU successfully starts one VM in a local ns and then another VM in a global ns with the same CID."
>+
>+ # diff_ns_global_host_connect_to_global_vm_ok
>+ "Run vsock_test client in global ns with server in VM in another global ns."
>+
>+ # diff_ns_global_host_connect_to_local_vm_fails
>+ "Run socat to test a process in a global ns fails to connect to a VM in a local ns."
>+
>+ # diff_ns_global_vm_connect_to_global_host_ok
>+ "Run vsock_test client in VM in a global ns with server in another global ns."
>+
>+ # diff_ns_global_vm_connect_to_local_host_fails
>+ "Run socat to test a VM in a global ns fails to connect to a host process in a local ns."
>+
>+ # diff_ns_local_host_connect_to_local_vm_fails
>+ "Run socat to test a host process in a local ns fails to connect to a VM in another local ns."
>+
>+ # diff_ns_local_vm_connect_to_local_host_fails
>+ "Run socat to test a VM in a local ns fails to connect to a host process in another local ns."
>+
>+ # diff_ns_global_to_local_loopback_local_fails
>+ "Run socat to test a loopback vsock in a global ns fails to connect to a vsock in a local ns."
>+
>+ # diff_ns_local_to_global_loopback_fails
>+ "Run socat to test a loopback vsock in a local ns fails to connect to a vsock in a global ns."
>+
>+ # diff_ns_local_to_local_loopback_fails
>+ "Run socat to test a loopback vsock in a local ns fails to connect to a vsock in another local ns."
>+
>+ # diff_ns_global_to_global_loopback_ok
>+ "Run socat to test a loopback vsock in a global ns successfully connects to a vsock in another global ns."
>+
>+ # same_ns_local_loopback_ok
>+ "Run socat to test a loopback vsock in a local ns successfully connects to a vsock in the same ns."
>+
>+ # same_ns_local_host_connect_to_local_vm_ok
>+ "Run vsock_test client in a local ns with server in VM in same ns."
>+
>+ # same_ns_local_vm_connect_to_local_host_ok
>+ "Run vsock_test client in VM in a local ns with server in same ns."
>+)
>+
>+readonly USE_SHARED_VM=(vm_server_host_client vm_client_host_server vm_loopback)
>+readonly USE_INIT_NETNS=(
>+ global_same_cid_fails
>+ local_same_cid_ok
>+ global_local_same_cid_ok
>+ local_global_same_cid_ok
>+ diff_ns_global_host_connect_to_global_vm_ok
>+ diff_ns_global_host_connect_to_local_vm_fails
>+ diff_ns_global_vm_connect_to_global_host_ok
>+ diff_ns_global_vm_connect_to_local_host_fails
>+ diff_ns_local_host_connect_to_local_vm_fails
>+ diff_ns_local_vm_connect_to_local_host_fails
>+ diff_ns_global_to_local_loopback_local_fails
>+ diff_ns_local_to_global_loopback_fails
>+ diff_ns_local_to_local_loopback_fails
>+ diff_ns_global_to_global_loopback_ok
>+ same_ns_local_loopback_ok
>+ same_ns_local_host_connect_to_local_vm_ok
>+ same_ns_local_vm_connect_to_local_host_ok
> )
>+readonly MODES=("local" "global")
>
> readonly LOG_LEVEL_DEBUG=0
> readonly LOG_LEVEL_INFO=1
>@@ -58,6 +161,12 @@ readonly LOG_LEVEL_ERROR=3
>
> VERBOSE="${LOG_LEVEL_WARN}"
>
>+# Test pass/fail counters
>+cnt_pass=0
>+cnt_fail=0
>+cnt_skip=0
>+cnt_total=0
>+
> usage() {
> local name
> local desc
>@@ -77,7 +186,7 @@ usage() {
> for ((i = 0; i < ${#TEST_NAMES[@]}; i++)); do
> name=${TEST_NAMES[${i}]}
> desc=${TEST_DESCS[${i}]}
>- printf "\t%-35s%-35s\n" "${name}" "${desc}"
>+ printf "\t%-55s%-35s\n" "${name}" "${desc}"
> done
> echo
>
>@@ -89,21 +198,87 @@ die() {
> exit "${KSFT_FAIL}"
> }
>
>+add_namespaces() {
>+ # add namespaces local0, local1, global0, and global1
>+ for mode in "${MODES[@]}"; do
>+ ip netns add "${mode}0" 2>/dev/null
>+ ip netns add "${mode}1" 2>/dev/null
>+ done
>+}
>+
>+init_namespaces() {
>+ for mode in "${MODES[@]}"; do
>+ ns_set_mode "${mode}0" "${mode}"
>+ ns_set_mode "${mode}1" "${mode}"
>+
>+ log_host "set ns ${mode}0 to mode ${mode}"
>+ log_host "set ns ${mode}1 to mode ${mode}"
>+
>+ # we need lo for qemu port forwarding
>+ ip netns exec "${mode}0" ip link set dev lo up
>+ ip netns exec "${mode}1" ip link set dev lo up
>+ done
>+}
>+
>+del_namespaces() {
>+ for mode in "${MODES[@]}"; do
>+ ip netns del "${mode}0"
>+ ip netns del "${mode}1"
>+ log_host "removed ns ${mode}0"
>+ log_host "removed ns ${mode}1"
>+ done &>/dev/null
>+}
>+
>+ns_set_mode() {
>+ local ns=$1
>+ local mode=$2
>+
>+ echo "${mode}" | ip netns exec "${ns}" \
>+ tee /proc/sys/net/vsock/ns_mode &>/dev/null
>+}
>+
> vm_ssh() {
>- ssh -q -o UserKnownHostsFile=/dev/null -p ${SSH_HOST_PORT} localhost "$@"
>+ local ns_exec
>+
>+ if [[ "${1}" == none ]]; then
>+ local ns_exec=""
>+ else
>+ local ns_exec="ip netns exec ${1}"
>+ fi
>+
>+ shift
>+
>+ ${ns_exec} 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
>+ del_namespaces
>+}
>
>- # 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() {
>+ local pidfile
>+
>+ for pidfile in "$@"; do
>+ if [[ -s "${pidfile}" ]]; then
>+ pkill -SIGTERM -F "${pidfile}" 2>&1 > /dev/null
>+ fi
>+
>+ # If failure occurred during or before qemu start up, then we need
>+ # to clean this up ourselves.
>+ if [[ -e "${pidfile}" ]]; then
>+ rm -f "${pidfile}"
>+ fi
>+ done
>+}
>+
>+terminate_pids() {
>+ local pid
>+
>+ for pid in "$@"; do
>+ kill -SIGTERM "${pid}" &>/dev/null || :
>+ done
> }
>
> check_args() {
>@@ -133,7 +308,7 @@ check_args() {
> }
>
> check_deps() {
>- for dep in vng ${QEMU} busybox pkill ssh; do
>+ for dep in vng ${QEMU} busybox pkill ssh socat; do
> if [[ ! -x $(command -v "${dep}") ]]; then
> echo -e "skip: dependency ${dep} not found!\n"
> exit "${KSFT_SKIP}"
>@@ -170,6 +345,20 @@ check_vng() {
> fi
> }
>
>+check_socat() {
>+ local support_string
>+
>+ support_string="$(socat -V)"
>+
>+ if [[ "${support_string}" != *"WITH_VSOCK 1"* ]]; then
>+ die "err: socat is missing vsock support"
>+ fi
>+
>+ if [[ "${support_string}" != *"WITH_UNIX 1"* ]]; then
>+ die "err: socat is missing unix support"
>+ fi
>+}
>+
> handle_build() {
> if [[ ! "${BUILD}" -eq 1 ]]; then
> return
>@@ -194,9 +383,14 @@ handle_build() {
> }
>
> vm_start() {
>+ local cid=$1
>+ local ns=$2
>+ local pidfile=$3
> local logfile=/dev/null
> local verbose_opt=""
>+ local qemu_opts=""
> local kernel_opt=""
>+ local ns_exec=""
> local qemu
>
> qemu=$(command -v "${QEMU}")
>@@ -206,27 +400,37 @@ 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 \
>+ ${QEMU_OPTS} -device vhost-vsock-pci,guest-cid=${cid} \
>+ --pidfile ${pidfile}
>+ "
>+
> if [[ "${BUILD}" -eq 1 ]]; then
> kernel_opt="${KERNEL_CHECKOUT}"
> fi
>
>- vng \
>+ if [[ "${ns}" != "none" ]]; then
>+ ns_exec="ip netns exec ${ns}"
>+ fi
>+
>+ ${ns_exec} vng \
> --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() {
>+ local ns=$1
> local i
>
> i=0
>@@ -234,7 +438,8 @@ vm_wait_for_ssh() {
> if [[ ${i} -gt ${WAIT_PERIOD_MAX} ]]; then
> die "Timed out waiting for guest ssh"
> fi
>- if vm_ssh -- true; then
>+
>+ if vm_ssh "${ns}" -- true; then
> break
> fi
> i=$(( i + 1 ))
>@@ -269,6 +474,7 @@ wait_for_listener()
> grep -q "${pattern}"; then
> break
> fi
>+
> sleep "${interval}"
> done
>
>@@ -278,17 +484,29 @@ wait_for_listener()
> }
>
> vm_wait_for_listener() {
>- local port=$1
>+ local ns=$1
>+ local port=$2
>+
>+ log "Waiting for listener on port ${port} on vm"
>
>- vm_ssh <<EOF
>+ vm_ssh "${ns}" <<EOF
> $(declare -f wait_for_listener)
> wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX}
> EOF
> }
>
> host_wait_for_listener() {
>- wait_for_listener "${TEST_HOST_PORT_LISTENER}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}"
>+ local ns=$1
>+ local port=$2
>
>+ if [[ "${ns}" == none ]]; then
>+ wait_for_listener "${port}" "${WAIT_PERIOD}" "${WAIT_PERIOD_MAX}"
>+ else
>+ ip netns exec "${ns}" bash <<-EOF
>+ $(declare -f wait_for_listener)
>+ wait_for_listener ${port} ${WAIT_PERIOD} ${WAIT_PERIOD_MAX}
>+ EOF
>+ fi
> }
>
> log() {
>@@ -427,51 +645,506 @@ test_vm_client_host_server() {
> }
>
> test_vm_loopback() {
>+ vm_ssh "none" modprobe vsock_loopback || :
> vm_vsock_test "none" "server" 1 "${TEST_HOST_PORT_LISTENER}"
> vm_vsock_test "none" "client" "127.0.0.1" 1 "${TEST_HOST_PORT_LISTENER}"
> }
>
>+test_host_vsock_ns_mode_ok() {
>+ add_namespaces
>+
>+ for mode in "${MODES[@]}"; do
>+ if ! ns_set_mode "${mode}0" "${mode}"; then
>+ del_namespaces
>+ return "${KSFT_FAIL}"
>+ fi
>+ done
>
>+ del_namespaces
> }
>
>-test_vm_client_host_server() {
>+test_host_vsock_ns_mode_write_once_ok() {
>+ add_namespaces
>
>- ${VSOCK_TEST} \
>- --mode "server" \
>- --control-port "${TEST_HOST_PORT_LISTENER}" \
>- --peer-cid "${VSOCK_CID}" 2>&1 | log_host &
>+ for mode in "${MODES[@]}"; do
>+ local ns="${mode}0"
>+ if ! ns_set_mode "${ns}" "${mode}"; then
>+ del_namespaces
>+ return "${KSFT_FAIL}"
>+ fi
>
>- host_wait_for_listener
>+ # try writing again and expect failure
>+ if ns_set_mode "${ns}" "${mode}"; then
>+ del_namespaces
>+ return "${KSFT_FAIL}"
>+ fi
>+ done
>
>- 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
>+ del_namespaces
>
>- return $?
>+ return "${KSFT_PASS}"
> }
>
>-test_vm_loopback() {
>- local port=60000 # non-forwarded local port
>+namespaces_can_boot_same_cid() {
>+ local ns0=$1
>+ local ns1=$2
>+ local pidfile1 pidfile2
>+ local cid=20
>+ readonly cid
>+ local rc
>
>- vm_ssh -- "${VSOCK_TEST}" \
>- --mode=server \
>- --control-port="${port}" \
>- --peer-cid=1 2>&1 | log_guest &
>+ pidfile1=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ vm_start "${cid}" "${ns0}" "${pidfile1}"
>
>- vm_wait_for_listener "${port}"
>+ pidfile2=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ vm_start "${cid}" "${ns1}" "${pidfile2}"
>
>- vm_ssh -- "${VSOCK_TEST}" \
>- --mode=client \
>- --control-host="127.0.0.1" \
>- --control-port="${port}" \
>- --peer-cid=1 2>&1 | log_guest
>+ rc=$?
>+ terminate_pidfiles "${pidfile1}" "${pidfile2}"
>
>- return $?
>+ return $rc
>+}
>+
>+test_global_same_cid_fails() {
>+ if namespaces_can_boot_same_cid "global0" "global1"; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+}
>+
>+test_local_global_same_cid_ok() {
>+ if namespaces_can_boot_same_cid "local0" "global0"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_global_local_same_cid_ok() {
>+ if namespaces_can_boot_same_cid "global0" "local0"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_local_same_cid_ok() {
>+ if namespaces_can_boot_same_cid "local0" "local0"; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+}
>+
>+test_diff_ns_global_host_connect_to_global_vm_ok() {
>+ local pids pid pidfile
>+ local ns0 ns1 port
>+ declare -a pids
>+ local unixfile
>+ ns0="global0"
>+ ns1="global1"
>+ port=1234
>+ local rc
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+
>+ if ! vm_start "${VSOCK_CID}" "${ns0}" "${pidfile}"; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ unixfile=$(mktemp -u /tmp/XXXX.sock)
>+ ip netns exec "${ns1}" \
>+ socat TCP-LISTEN:"${TEST_HOST_PORT}",fork \
>+ UNIX-CONNECT:"${unixfile}" &
>+ pids+=($!)
>+ host_wait_for_listener "${ns1}" "${TEST_HOST_PORT}"
>+
>+ ip netns exec "${ns0}" socat UNIX-LISTEN:"${unixfile}",fork \
>+ TCP-CONNECT:localhost:"${TEST_HOST_PORT}" &
>+ pids+=($!)
>+
>+ vm_vsock_test "${ns0}" "server" 2 "${TEST_GUEST_PORT}"
>+ vm_wait_for_listener "${ns0}" "${TEST_GUEST_PORT}"
>+ host_vsock_test "${ns1}" "client" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"
>+ rc=$?
>+
>+ for pid in "${pids[@]}"; do
>+ if [[ "$(jobs -p)" = *"${pid}"* ]]; then
>+ kill -SIGTERM "${pid}" &>/dev/null
>+ fi
>+ done
>+
>+ terminate_pidfiles "${pidfile}"
>+
>+ if [[ $rc -ne 0 ]]; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+}
>+
>+test_diff_ns_global_host_connect_to_local_vm_fails() {
>+ local ns0="global0"
>+ local ns1="local0"
>+ local port=12345
>+ local pidfile
>+ local result
>+ local pid
>+
>+ outfile=$(mktemp)
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ if ! vm_start "${VSOCK_CID}" "${ns1}" "${pidfile}"; then
>+ log_host "failed to start vm (cid=${VSOCK_CID}, ns=${ns0})"
>+ return $KSFT_FAIL
>+ fi
>+
>+ vm_wait_for_ssh "${ns1}"
>+ vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" &
>+ echo TEST | ip netns exec "${ns0}" \
>+ socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null
>+
>+ terminate_pidfiles "${pidfile}"
>+
>+ result=$(cat "${outfile}")
>+ rm -f "${outfile}"
>+
>+ if [[ "${result}" != TEST ]]; then
>+ return $KSFT_PASS
>+ fi
>+
>+ return $KSFT_FAIL
>+}
>+
>+test_diff_ns_global_vm_connect_to_global_host_ok() {
>+ local ns0="global0"
>+ local ns1="global1"
>+ local port=12345
>+ local unixfile
>+ local pidfile
>+ local pids
>+
>+ declare -a pids
>+
>+ log_host "Setup socat bridge from ns ${ns0} to ns ${ns1} over port ${port}"
>+
>+ unixfile=$(mktemp -u /tmp/XXXX.sock)
>+
>+ ip netns exec "${ns0}" \
>+ socat TCP-LISTEN:"${port}" UNIX-CONNECT:"${unixfile}" &
>+ pids+=($!)
>+
>+ ip netns exec "${ns1}" \
>+ socat UNIX-LISTEN:"${unixfile}" TCP-CONNECT:127.0.0.1:"${port}" &
>+ pids+=($!)
>+
>+ log_host "Launching ${VSOCK_TEST} in ns ${ns1}"
>+ host_vsock_test "${ns1}" "server" "${VSOCK_CID}" "${port}"
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ if ! vm_start "${VSOCK_CID}" "${ns0}" "${pidfile}"; then
>+ log_host "failed to start vm (cid=${cid}, ns=${ns0})"
>+ terminate_pids "${pids[@]}"
>+ rm -f "${unixfile}"
>+ return $KSFT_FAIL
>+ fi
>+
>+ vm_wait_for_ssh "${ns0}"
>+ vm_vsock_test "${ns0}" "client" "10.0.2.2" 2 "${port}"
>+ rc=$?
>+
>+ terminate_pidfiles "${pidfile}"
>+ terminate_pids "${pids[@]}"
>+ rm -f "${unixfile}"
>+
>+ if [[ ! $rc -eq 0 ]]; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+
>+}
>+
>+test_diff_ns_global_vm_connect_to_local_host_fails() {
>+ local ns0="global0"
>+ local ns1="local0"
>+ local port=12345
>+ local pidfile
>+ local result
>+ local pid
>+
>+ log_host "Launching socat in ns ${ns1}"
>+ outfile=$(mktemp)
>+ ip netns exec "${ns1}" socat VSOCK-LISTEN:${port} STDOUT &> "${outfile}" &
>+ pid=$!
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ if ! vm_start "${VSOCK_CID}" "${ns0}" "${pidfile}"; then
>+ log_host "failed to start vm (cid=${cid}, ns=${ns0})"
>+ terminate_pids "${pid}"
>+ rm -f "${outfile}"
>+ return $KSFT_FAIL
>+ fi
>+
>+ vm_wait_for_ssh "${ns0}"
>+
>+ vm_ssh "${ns0}" -- \
>+ bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest
>+
>+ terminate_pidfiles "${pidfile}"
>+ terminate_pids "${pid}"
>+
>+ result=$(cat "${outfile}")
>+ rm -f "${outfile}"
>+
>+ if [[ "${result}" != TEST ]]; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_diff_ns_local_host_connect_to_local_vm_fails() {
>+ local ns0="local0"
>+ local ns1="local1"
>+ local port=12345
>+ local pidfile
>+ local result
>+ local pid
>+
>+ outfile=$(mktemp)
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ if ! vm_start "${VSOCK_CID}" "${ns1}" "${pidfile}"; then
>+ log_host "failed to start vm (cid=${cid}, ns=${ns0})"
>+ return $KSFT_FAIL
>+ fi
>+
>+ vm_wait_for_ssh "${ns1}"
>+ vm_ssh "${ns1}" -- socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" &
>+ echo TEST | ip netns exec "${ns0}" \
>+ socat STDIN VSOCK-CONNECT:"${VSOCK_CID}":"${port}" 2>/dev/null
>+
>+ terminate_pidfiles "${pidfile}"
>+
>+ result=$(cat "${outfile}")
>+ rm -f "${outfile}"
>+
>+ if [[ "${result}" != TEST ]]; then
>+ return $KSFT_PASS
>+ fi
>+
>+ return $KSFT_FAIL
>+}
>+
>+test_diff_ns_local_vm_connect_to_local_host_fails() {
>+ local ns0="local0"
>+ local ns1="local1"
>+ local port=12345
>+ local pidfile
>+ local result
>+ local pid
>+
>+ log_host "Launching socat in ns ${ns1}"
>+ outfile=$(mktemp)
>+ ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT &> "${outfile}" &
>+ pid=$!
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+ if ! vm_start "${VSOCK_CID}" "${ns0}" "${pidfile}"; then
>+ log_host "failed to start vm (cid=${cid}, ns=${ns0})"
>+ rm -f "${outfile}"
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ vm_wait_for_ssh "${ns0}"
>+
>+ vm_ssh "${ns0}" -- \
>+ bash -c "echo TEST | socat STDIN VSOCK-CONNECT:2:${port}" 2>&1 | log_guest
>+
>+ terminate_pidfiles "${pidfile}"
>+ terminate_pids "${pid}"
>+
>+ result=$(cat "${outfile}")
>+ rm -f "${outfile}"
>+
>+ if [[ "${result}" != TEST ]]; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+__test_loopback_two_netns() {
>+ local ns0=$1
>+ local ns1=$2
>+ local port=12345
>+ local result
>+ local pid
>+
>+ modprobe vsock_loopback &> /dev/null || :
>+
>+ log_host "Launching socat in ns ${ns1}"
>+ outfile=$(mktemp)
>+ ip netns exec "${ns1}" socat VSOCK-LISTEN:"${port}" STDOUT > "${outfile}" 2>/dev/null &
>+ pid=$!
>+
>+ log_host "Launching socat in ns ${ns0}"
>+ echo TEST | ip netns exec "${ns0}" socat STDIN VSOCK-CONNECT:1:"${port}" 2>/dev/null
>+ terminate_pids "${pid}"
>+
>+ result=$(cat "${outfile}")
>+ rm -f "${outfile}"
>+
>+ if [[ "${result}" == TEST ]]; then
>+ return 0
>+ fi
>+
>+ return 1
>+}
>+
>+test_diff_ns_global_to_local_loopback_local_fails() {
>+ if ! __test_loopback_two_netns "global0" "local0"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_diff_ns_local_to_global_loopback_fails() {
>+ if ! __test_loopback_two_netns "local0" "global0"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_diff_ns_local_to_local_loopback_fails() {
>+ if ! __test_loopback_two_netns "local0" "local1"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_diff_ns_global_to_global_loopback_ok() {
>+ if __test_loopback_two_netns "global0" "global1"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_same_ns_local_loopback_ok() {
>+ if __test_loopback_two_netns "local0" "local0"; then
>+ return "${KSFT_PASS}"
>+ fi
>+
>+ return "${KSFT_FAIL}"
>+}
>+
>+test_same_ns_local_host_connect_to_local_vm_ok() {
>+ local ns="local0"
>+ local port=1234
>+ local pidfile
>+ local rc
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+
>+ if ! vm_start "${VSOCK_CID}" "${ns}" "${pidfile}"; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ vm_vsock_test "${ns}" "server" 2 "${TEST_GUEST_PORT}"
>+ host_vsock_test "${ns}" "client" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"
>+ rc=$?
>+
>+ terminate_pidfiles "${pidfile}"
>+
>+ if [[ $rc -ne 0 ]]; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+}
>+
>+test_same_ns_local_vm_connect_to_local_host_ok() {
>+ local ns="local0"
>+ local port=1234
>+ local pidfile
>+ local rc
>+
>+ pidfile=$(mktemp /tmp/qemu_vsock_vmtest_XXXX.pid)
>+
>+ if ! vm_start "${VSOCK_CID}" "${ns}" "${pidfile}"; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ vm_vsock_test "${ns}" "server" 2 "${TEST_GUEST_PORT}"
>+ host_vsock_test "${ns}" "client" "127.0.0.1" "${VSOCK_CID}" "${TEST_HOST_PORT}"
>+ rc=$?
>+
>+ terminate_pidfiles "${pidfile}"
>+
>+ if [[ $rc -ne 0 ]]; then
>+ return "${KSFT_FAIL}"
>+ fi
>+
>+ return "${KSFT_PASS}"
>+}
>+
>+shared_vm_test() {
>+ local tname
>+
>+ tname="${1}"
>+
>+ for testname in "${USE_SHARED_VM[@]}"; do
>+ if [[ "${tname}" == "${testname}" ]]; then
>+ return 0
>+ fi
>+ done
>+
>+ return 1
> }
>
>-run_test() {
>+
>+init_netns_test() {
>+ local tname
>+
>+ tname="${1}"
>+
>+ for testname in "${USE_INIT_NETNS[@]}"; do
>+ if [[ "${tname}" == "${testname}" ]]; then
>+ return 0
>+ fi
>+ done
>+
>+ return 1
>+}
>+
>+check_result() {
>+ local rc num
>+
>+ rc=$1
>+ num=$(( cnt_total + 1 ))
>+
>+ if [[ ${rc} -eq $KSFT_PASS ]]; then
>+ cnt_pass=$(( cnt_pass + 1 ))
>+ echo "ok ${num} ${arg}"
>+ elif [[ ${rc} -eq $KSFT_SKIP ]]; then
>+ cnt_skip=$(( cnt_skip + 1 ))
>+ echo "ok ${num} ${arg} # SKIP"
>+ elif [[ ${rc} -eq $KSFT_FAIL ]]; then
>+ cnt_fail=$(( cnt_fail + 1 ))
>+ echo "not ok ${num} ${arg} # exit=$rc"
>+ fi
>+
>+ cnt_total=$(( cnt_total + 1 ))
>+}
>+
>+run_shared_vm_tests() {
>+ local start_shared_vm pidfile
> local host_oops_cnt_before
> local host_warn_cnt_before
> local vm_oops_cnt_before
>@@ -483,42 +1156,93 @@ run_test() {
> local name
> local rc
>
>- host_oops_cnt_before=$(dmesg | grep -c -i 'Oops')
>- host_warn_cnt_before=$(dmesg --level=warn | wc -l)
>- vm_oops_cnt_before=$(vm_ssh -- dmesg | grep -c -i 'Oops')
>- vm_warn_cnt_before=$(vm_ssh -- dmesg --level=warn | wc -l)
>+ start_shared_vm=0
>
>- name=$(echo "${1}" | awk '{ print $1 }')
>- eval test_"${name}"
>- rc=$?
>+ for arg in "${ARGS[@]}"; do
>+ if shared_vm_test "${arg}"; then
>+ start_shared_vm=1
>+ break
>+ fi
>+ done
>
>- 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}"
>- rc=$KSFT_FAIL
>+ pidfile=""
>+ if [[ "${start_shared_vm}" == 1 ]]; then
>+ pidfile=$(mktemp $PIDFILE_TEMPLATE)
>+ log_host "Booting up VM"
>+ vm_start "${VSOCK_CID}" "none" "${pidfile}"
>+ vm_wait_for_ssh "none"
>+ log_host "VM booted up"
> fi
>
>- host_warn_cnt_after=$(dmesg --level=warn | wc -l)
>- if [[ ${host_warn_cnt_after} -gt ${host_warn_cnt_before} ]]; then
>- echo "FAIL: kernel warning detected on host" | log_host "${name}"
>- rc=$KSFT_FAIL
>- fi
>+ for arg in "${ARGS[@]}"; do
>+ if ! shared_vm_test "${arg}"; then
>+ continue
>+ 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}"
>- rc=$KSFT_FAIL
>- fi
>+ host_oops_cnt_before=$(dmesg | grep -c -i 'Oops')
>+ host_warn_cnt_before=$(dmesg --level=warn | wc -l)
>+ vm_oops_cnt_before=$(vm_ssh none -- dmesg | grep -c -i 'Oops')
>+ vm_warn_cnt_before=$(vm_ssh none -- dmesg --level=warn | wc -l)
>+
>+ name=$(echo "${arg}" | awk '{ print $1 }')
>+ log_host "Executing test_${name}"
>+ eval test_"${name}"
>+ rc=$?
>+
>+ 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}"
>+ rc=$KSFT_FAIL
>+ fi
>+
>+ host_warn_cnt_after=$(dmesg --level=warn | wc -l)
>+ if [[ ${host_warn_cnt_after} -gt ${host_warn_cnt_before} ]]; then
>+ echo "FAIL: kernel warning detected on host" | log_host "${name}"
>+ rc=$KSFT_FAIL
>+ fi
>+
>+ vm_oops_cnt_after=$(vm_ssh none -- 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}"
>+ rc=$KSFT_FAIL
>+ fi
>+
>+ vm_warn_cnt_after=$(vm_ssh none -- dmesg --level=warn | wc -l)
>+ if [[ ${vm_warn_cnt_after} -gt ${vm_warn_cnt_before} ]]; then
>+ echo "FAIL: kernel warning detected on vm" | log_host "${name}"
>+ rc=$KSFT_FAIL
>+ fi
>
>- vm_warn_cnt_after=$(vm_ssh -- dmesg --level=warn | wc -l)
>- if [[ ${vm_warn_cnt_after} -gt ${vm_warn_cnt_before} ]]; then
>- echo "FAIL: kernel warning detected on vm" | log_host "${name}"
>- rc=$KSFT_FAIL
>+ check_result "${rc}"
>+ done
>+
>+ if [[ -n "${pidfile}" ]]; then
>+ log_host "VM terminate"
>+ terminate_pidfiles "${pidfile}"
> fi
>+}
>+
>+run_isolated_vm_tests() {
>+ for arg in "${ARGS[@]}"; do
>+ if shared_vm_test "${arg}"; then
>+ continue
>+ fi
>
>- return "${rc}"
>+ add_namespaces
>+ if init_netns_test "${arg}"; then
>+ init_namespaces
>+ fi
>+
>+ name=$(echo "${arg}" | awk '{ print $1 }')
>+ log_host "Executing test_${name}"
>+ eval test_"${name}"
>+ check_result $?
>+
>+ del_namespaces
>+ done
> }
>
>+BUILD=0
> QEMU="qemu-system-$(uname -m)"
>
> while getopts :hvsq:b o
>@@ -543,34 +1267,13 @@ fi
> check_args "${ARGS[@]}"
> check_deps
> check_vng
>+check_socat
> handle_build
>
> echo "1..${#ARGS[@]}"
>
>-log_host "Booting up VM"
>-vm_start
>-vm_wait_for_ssh
>-log_host "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
>+run_shared_vm_tests
>+run_isolated_vm_tests
>
> echo "SUMMARY: PASS=${cnt_pass} SKIP=${cnt_skip} FAIL=${cnt_fail}"
> echo "Log: ${LOG}"
>
>--
>2.47.3
>
Powered by blists - more mailing lists