[PATCH net-next v8 14/14] selftests/vsock: add tests for module loading order

Bobby Eshleman
2025-10-23T18:28:18Z

From: Bobby Eshleman <bobbyeshleman@meta.com>

Add tests to check that module loading order does not break
vsock_loopback. Because vsock_loopback has some per-namespace data
structure initialization that affects vsock namespace modes, lets make
sure that namespace modes are respected and loopback sockets are
functional even when the namespaces and modes are set prior to loading
the vsock_loopback module.

Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
---
tools/testing/selftests/vsock/vmtest.sh | 138 ++++++++++++++++++++++++++++++++
1 file changed, 138 insertions(+)

diff --git a/tools/testing/selftests/vsock/vmtest.sh b/tools/testing/selftests/vsock/vmtest.sh
index 014cecd93858..9aa3200b160f 100755
--- a/tools/testing/selftests/vsock/vmtest.sh
+++ b/tools/testing/selftests/vsock/vmtest.sh
@@ -68,6 +68,8 @@ readonly TEST_NAMES=(
ns_delete_vm_ok
ns_delete_host_ok
ns_delete_both_ok
+ ns_loopback_global_global_late_module_load_ok
+ ns_loopback_local_local_late_module_load_fails
)
readonly TEST_DESCS=(
# vm_server_host_client
@@ -153,6 +155,12 @@ readonly TEST_DESCS=(

# ns_delete_both_ok
"Check that deleting the VM and host's namespaces does not break the socket connection"
+
+ # ns_loopback_global_global_late_module_load_ok
+ "Test that loopback still works in global namespaces initialized prior to loading the vsock_loopback kmod"
+
+ # ns_loopback_local_local_late_module_load_fails
+ "Test that loopback connections still fail between local namespaces initialized prior to loading the vsock_loopback kmod"
)

readonly USE_SHARED_VM=(vm_server_host_client vm_client_host_server vm_loopback)
@@ -914,6 +922,30 @@ test_ns_diff_local_vm_connect_to_local_host_fails() {
return "${KSFT_FAIL}"
}

+unload_module() {
+ local module=$1
+ local retries=5
+ readonly retries
+ local delay=1
+ local i
+
+ # Sometimes previously executed tests may result in a delayed release
+ # of the reference to the vsock_loopback module and result in the
+ # module being unremovable. For that reason, we use retries to allow
+ # some time for those references to be dropped.
+ for ((i = 0; i < ${retries}; i++)); do
+ modprobe -r "${module}" 2>/dev/null || :
+
+ if [[ "$(lsmod | grep -c ${module})" -eq 0 ]]; then
+ return 0
+ fi
+
+ sleep ${delay}
+ done
+
+ return 1
+}
+
__test_loopback_two_netns() {
local ns0=$1
local ns1=$2
@@ -1266,6 +1298,112 @@ test_ns_delete_both_ok() {
check_ns_changes_dont_break_connection "both" "delete"
}

+test_ns_loopback_global_global_late_module_load_ok() {
+ declare -a pids
+ local unixfile
+ local ns0 ns1
+ local pids
+ local port
+
+ if ! unload_module vsock_loopback; then
+ log_host "Unable to unload vsock_loopback, skipping..."
+ return "${KSFT_SKIP}"
+ fi
+
+ ns0=loopback_ns0
+ ns1=loopback_ns1
+
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ ip netns add "${ns0}"
+ ip netns add "${ns1}"
+ ns_set_mode "${ns0}" global
+ ns_set_mode "${ns1}" global
+ ip netns exec "${ns0}" ip link set dev lo up
+ ip netns exec "${ns1}" ip link set dev lo up
+
+ modprobe vsock_loopback &> /dev/null || :
+
+ unixfile=$(mktemp -u /tmp/XXXX.sock)
+ port=321
+ ip netns exec "${ns1}" \
+ socat TCP-LISTEN:"${port}",fork \
+ UNIX-CONNECT:"${unixfile}" &
+ pids+=($!)
+
+ host_wait_for_listener "${ns1}" "${port}"
+ ip netns exec "${ns0}" socat UNIX-LISTEN:"${unixfile}",fork \
+ TCP-CONNECT:localhost:"${port}" &
+ pids+=($!)
+
+ if ! host_vsock_test "${ns0}" "server" 1 "${port}"; then
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ terminate_pids "${pids[@]}"
+ return "${KSFT_FAIL}"
+ fi
+
+ if ! host_vsock_test "${ns1}" "127.0.0.1" 1 "${port}"; then
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ terminate_pids "${pids[@]}"
+ return "${KSFT_FAIL}"
+ fi
+
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ terminate_pids "${pids[@]}"
+
+ return "${KSFT_PASS}"
+}
+
+test_ns_loopback_local_local_late_module_load_fails() {
+ declare -a pids
+ local ns0 ns1
+ local outfile
+ local pids
+ local rc
+
+ if ! unload_module vsock_loopback; then
+ log_host "Unable to unload vsock_loopback, skipping..."
+ return "${KSFT_SKIP}"
+ fi
+
+ ns0=loopback_ns0
+ ns1=loopback_ns1
+
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ ip netns add "${ns0}"
+ ip netns add "${ns1}"
+ ns_set_mode "${ns0}" local
+ ns_set_mode "${ns1}" local
+
+ modprobe vsock_loopback &> /dev/null || :
+
+ outfile=$(mktemp /tmp/XXXX.vmtest.out)
+ ip netns exec "${ns0}" socat VSOCK-LISTEN:${port} STDOUT \
+ > "${outfile}" 2>/dev/null &
+ pids+=($!)
+
+ echo TEST | \
+ ip netns exec "${ns1}" socat STDIN VSOCK-CONNECT:1:${port} \
+ 2>/dev/null
+
+ if grep -q "TEST" "${outfile}" 2>/dev/null; then
+ rc="${KSFT_FAIL}"
+ else
+ rc="${KSFT_PASS}"
+ fi
+
+ ip netns del "${ns0}" &>/dev/null || :
+ ip netns del "${ns1}" &>/dev/null || :
+ terminate_pids "${pids[@]}"
+ rm -f "${outfile}"
+
+ return "${rc}"
+}
+
shared_vm_test() {
local tname

--
2.47.3