summaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/rdma
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2026-09-02 09:55:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2026-09-02 11:08:21 -0400
commit4617721c502b2ddaa4e324e86da4997edf738fa5 (patch)
tree350aa83b47da0b574a814795392b20b0bed83cbc /tools/testing/selftests/rdma
downloadlinux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz
linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'tools/testing/selftests/rdma')
-rw-r--r--tools/testing/selftests/rdma/Makefile9
-rw-r--r--tools/testing/selftests/rdma/config5
-rwxr-xr-xtools/testing/selftests/rdma/rxe_ipv6.sh65
-rwxr-xr-xtools/testing/selftests/rdma/rxe_netns_names.sh334
-rwxr-xr-xtools/testing/selftests/rdma/rxe_rping_between_netns.sh92
-rwxr-xr-xtools/testing/selftests/rdma/rxe_sent_rcvd_bytes.sh75
-rwxr-xr-xtools/testing/selftests/rdma/rxe_socket_with_netns.sh82
-rwxr-xr-xtools/testing/selftests/rdma/rxe_test_NETDEV_UNREGISTER.sh65
8 files changed, 727 insertions, 0 deletions
diff --git a/tools/testing/selftests/rdma/Makefile b/tools/testing/selftests/rdma/Makefile
new file mode 100644
index 000000000..a91c14c45
--- /dev/null
+++ b/tools/testing/selftests/rdma/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+TEST_PROGS := rxe_rping_between_netns.sh \
+ rxe_ipv6.sh \
+ rxe_socket_with_netns.sh \
+ rxe_test_NETDEV_UNREGISTER.sh \
+ rxe_sent_rcvd_bytes.sh \
+ rxe_netns_names.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/rdma/config b/tools/testing/selftests/rdma/config
new file mode 100644
index 000000000..e1ff54ec0
--- /dev/null
+++ b/tools/testing/selftests/rdma/config
@@ -0,0 +1,5 @@
+CONFIG_TUN
+CONFIG_VETH
+CONFIG_DUMMY
+CONFIG_NET_NS
+CONFIG_RDMA_RXE
diff --git a/tools/testing/selftests/rdma/rxe_ipv6.sh b/tools/testing/selftests/rdma/rxe_ipv6.sh
new file mode 100755
index 000000000..32dad687a
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_ipv6.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# Configuration
+NS_NAME="net6"
+VETH_HOST="veth0"
+VETH_NS="veth1"
+RXE_NAME="rxe6"
+PORT=4791
+IP6_ADDR="2001:db8::1/64"
+
+source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
+
+exec > /dev/null
+
+# Cleanup function to run on exit (even on failure)
+cleanup() {
+ ip netns del "$NS_NAME" 2>/dev/null
+ modprobe -r rdma_rxe 2>/dev/null
+ echo "Done."
+}
+trap cleanup EXIT
+
+# 1. Prerequisites check
+for mod in tun veth rdma_rxe; do
+ if ! modinfo "$mod" >/dev/null 2>&1; then
+ echo "SKIP: Kernel module '$mod' not found." >&2
+ exit $KSFT_SKIP
+ fi
+done
+
+modprobe rdma_rxe
+
+# 2. Setup Namespace and Networking
+echo "Setting up IPv6 network namespace..."
+ip netns add "$NS_NAME"
+ip link add "$VETH_HOST" type veth peer name "$VETH_NS"
+ip link set "$VETH_NS" netns "$NS_NAME"
+ip netns exec "$NS_NAME" ip addr add "$IP6_ADDR" dev "$VETH_NS"
+ip netns exec "$NS_NAME" ip link set "$VETH_NS" up
+ip link set "$VETH_HOST" up
+
+# 3. Add RDMA Link
+echo "Adding RDMA RXE link..."
+if ! ip netns exec "$NS_NAME" rdma link add "$RXE_NAME" type rxe netdev "$VETH_NS"; then
+ echo "Error: Failed to create RXE link."
+ exit 1
+fi
+
+# 4. Verification: Port should be listening
+# Using -H to skip headers and -q for quiet exit codes
+if ! ip netns exec "$NS_NAME" ss -Hul6n sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT is NOT listening after link creation."
+ exit 1
+fi
+echo "Verified: Port $PORT is active."
+
+# 5. Removal and Verification
+echo "Deleting RDMA link..."
+ip netns exec "$NS_NAME" rdma link del "$RXE_NAME"
+
+if ip netns exec "$NS_NAME" ss -Hul6n sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT still active after link deletion."
+ exit 1
+fi
+echo "Verified: Port $PORT closed successfully."
diff --git a/tools/testing/selftests/rdma/rxe_netns_names.sh b/tools/testing/selftests/rdma/rxe_netns_names.sh
new file mode 100755
index 000000000..f40118407
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_netns_names.sh
@@ -0,0 +1,334 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Exercise RDMA device name handling across network namespaces.
+
+source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
+
+NAME_PREFIX="rxe_netns_names_$$"
+NETDEV_PREFIX="rxn$$"
+NS1="${NAME_PREFIX}ns1"
+NS2="${NAME_PREFIX}ns2"
+RXE_A="${NAME_PREFIX}rxe_a"
+RXE_B="${NAME_PREFIX}rxe_b"
+RXE_SAME="${NAME_PREFIX}rxe_same"
+RXE_NEW="${NAME_PREFIX}rxe_new"
+DUMMY_A="${NETDEV_PREFIX}a"
+DUMMY_B="${NETDEV_PREFIX}b"
+OLD_MODE=""
+MODE_CHANGED=0
+MODS=("dummy" "rdma_rxe")
+TEST_SAME_NAMES="same RDMA device name can exist in two net namespaces"
+TEST_MOVE_CONFLICT="move without rename fails on destination name conflict"
+TEST_MOVE_RENAME="move then rename succeeds"
+TEST_COMBINED_MOVE_RENAME="move with requested destination name succeeds"
+TEST_SAME_NETNS_DUP_RENAME="same-netns rename rejects duplicate name"
+TEST_TEARDOWN_RETURN="netns delete returns device to init_net and renames on conflict"
+
+ksft_skip()
+{
+ ktap_skip_all "$*"
+ exit "$KSFT_SKIP"
+}
+
+fail()
+{
+ ktap_exit_fail_msg "$*"
+}
+
+need_cmd()
+{
+ command -v "$1" >/dev/null 2>&1 || ksft_skip "missing command: $1"
+}
+
+rdma_ns()
+{
+ local ns=$1
+
+ shift
+ ip netns exec "$ns" rdma "$@"
+}
+
+rdma_dev_exists()
+{
+ local ns=$1
+ local dev=$2
+
+ if [ -n "$ns" ]; then
+ rdma_ns "$ns" dev show "$dev" >/dev/null 2>&1
+ else
+ rdma dev show "$dev" >/dev/null 2>&1
+ fi
+}
+
+add_dummy()
+{
+ local netdev=$1
+
+ ip link add "$netdev" type dummy || return 1
+ ip link set "$netdev" up || return 1
+}
+
+add_rxe()
+{
+ local dev=$1
+ local netdev=$2
+
+ rdma link add "$dev" type rxe netdev "$netdev"
+}
+
+rdma_dev_on_netdev()
+{
+ local netdev=$1
+
+ rdma link show 2>/dev/null | awk -v want="$netdev" '
+ {
+ for (i = 1; i < NF; i++)
+ if ($i == "netdev" && $(i + 1) == want) {
+ dev = $2
+ sub(/\/.*/, "", dev)
+ print dev
+ exit
+ }
+ }'
+}
+
+wait_rdma_dev_on_netdev()
+{
+ local netdev=$1
+ local dev
+ local i
+
+ for i in $(seq 1 50); do
+ dev=$(rdma_dev_on_netdev "$netdev")
+ if [ -n "$dev" ]; then
+ echo "$dev"
+ return 0
+ fi
+ sleep 0.1
+ done
+
+ return 1
+}
+
+# ip link del returns after NETDEV_UNREGISTER, but rxe tears the RDMA device
+# down asynchronously via ib_unregister_device_queued(). Wait until our names
+# are gone.
+wait_rdma_devs_gone()
+{
+ local i name ns
+ local names=("$RXE_A" "$RXE_B" "$RXE_SAME" "$RXE_NEW")
+
+ for i in $(seq 1 50); do
+ local found=0
+
+ for name in "${names[@]}"; do
+ if rdma_dev_exists "" "$name"; then
+ found=1
+ break
+ fi
+ for ns in "$NS1" "$NS2"; do
+ ip netns exec "$ns" true 2>/dev/null || continue
+ if rdma_dev_exists "$ns" "$name"; then
+ found=1
+ break 2
+ fi
+ done
+ done
+
+ [ "$found" -eq 0 ] && return 0
+ sleep 0.1
+ done
+
+ return 1
+}
+
+setup_devs()
+{
+ cleanup_devs || return 1
+
+ add_dummy "$DUMMY_A" || return 1
+ add_dummy "$DUMMY_B" || return 1
+
+ add_rxe "$RXE_A" "$DUMMY_A" || return 1
+ add_rxe "$RXE_B" "$DUMMY_B" || return 1
+}
+
+cleanup_devs()
+{
+ ip link del "$DUMMY_A" 2>/dev/null
+ ip link del "$DUMMY_B" 2>/dev/null
+ wait_rdma_devs_gone
+}
+
+setup()
+{
+ OLD_MODE=$(rdma system show 2>/dev/null |
+ sed -n 's/.*netns \([^ ]*\).*/\1/p')
+ [ -n "$OLD_MODE" ] || ksft_skip "failed to read RDMA netns mode"
+
+ rdma system set netns exclusive >/dev/null 2>&1 ||
+ ksft_skip "rdma netns exclusive mode is not supported"
+ MODE_CHANGED=1
+
+ ip netns add "$NS1" || return 1
+ ip netns add "$NS2" || return 1
+}
+
+# ip netns del returns before rdma_dev_exit_net() removes the net from
+# rdma_nets. rdma_compatdev_set() returns -EBUSY until that completes, so
+# retry the mode restore instead of leaving the system in exclusive mode.
+restore_netns_mode()
+{
+ local i
+
+ [ "$MODE_CHANGED" -eq 1 ] || return 0
+
+ for i in $(seq 1 50); do
+ if rdma system set netns "$OLD_MODE" >/dev/null 2>&1; then
+ MODE_CHANGED=0
+ return 0
+ fi
+ sleep 0.1
+ done
+
+ echo "warning: failed to restore RDMA netns mode to $OLD_MODE" >&2
+ return 1
+}
+
+cleanup()
+{
+ cleanup_devs
+
+ ip netns del "$NS1" 2>/dev/null
+ ip netns del "$NS2" 2>/dev/null
+
+ restore_netns_mode
+
+ for m in "${MODS[@]}"; do
+ modprobe -r "$m" 2>/dev/null
+ done
+}
+
+rdma_supports_combined_move_rename()
+{
+ rdma dev help 2>&1 | grep -Eq 'netns .*name|name .*netns'
+}
+
+[ "$(id -u)" -eq 0 ] || ksft_skip "must be run as root"
+need_cmd ip
+need_cmd rdma
+need_cmd modprobe
+
+trap cleanup EXIT
+
+for m in "${MODS[@]}"; do
+ modinfo "$m" >/dev/null 2>&1 || ksft_skip "module $m not found"
+ modprobe "$m" || fail "failed to load $m"
+done
+
+setup || fail "failed to create net namespaces"
+
+ktap_print_header
+ktap_set_plan 6
+
+if setup_devs &&
+ rdma dev set "$RXE_A" netns "$NS1" &&
+ rdma_ns "$NS1" dev set "$RXE_A" name "$RXE_SAME" &&
+ rdma dev set "$RXE_B" netns "$NS2" &&
+ rdma_ns "$NS2" dev set "$RXE_B" name "$RXE_SAME" &&
+ rdma_dev_exists "$NS1" "$RXE_SAME" &&
+ rdma_dev_exists "$NS2" "$RXE_SAME"; then
+ ktap_test_pass "$TEST_SAME_NAMES"
+else
+ ktap_test_fail "$TEST_SAME_NAMES"
+fi
+cleanup_devs
+
+if ! setup_devs ||
+ ! rdma dev set "$RXE_A" netns "$NS1" ||
+ ! rdma_ns "$NS1" dev set "$RXE_A" name "$RXE_SAME" ||
+ ! rdma dev set "$RXE_B" netns "$NS2" ||
+ ! rdma_ns "$NS2" dev set "$RXE_B" name "$RXE_SAME"; then
+ ktap_test_fail "$TEST_MOVE_CONFLICT"
+elif rdma_ns "$NS1" dev set "$RXE_SAME" netns "$NS2" >/dev/null 2>&1; then
+ ktap_test_fail "$TEST_MOVE_CONFLICT"
+elif rdma_dev_exists "$NS1" "$RXE_SAME" &&
+ rdma_dev_exists "$NS2" "$RXE_SAME"; then
+ ktap_test_pass "$TEST_MOVE_CONFLICT"
+else
+ ktap_test_fail "$TEST_MOVE_CONFLICT"
+fi
+cleanup_devs
+
+if ! setup_devs; then
+ ktap_test_fail "$TEST_MOVE_RENAME"
+elif rdma dev set "$RXE_A" netns "$NS2" &&
+ rdma_ns "$NS2" dev set "$RXE_A" name "$RXE_NEW"; then
+ if rdma_dev_exists "$NS2" "$RXE_NEW" &&
+ ! rdma_dev_exists "" "$RXE_A"; then
+ ktap_test_pass "$TEST_MOVE_RENAME"
+ else
+ ktap_test_fail "$TEST_MOVE_RENAME"
+ fi
+else
+ ktap_test_fail "$TEST_MOVE_RENAME"
+fi
+cleanup_devs
+
+if ! rdma_supports_combined_move_rename; then
+ ktap_test_skip "$TEST_COMBINED_MOVE_RENAME"
+elif ! setup_devs; then
+ ktap_test_fail "$TEST_COMBINED_MOVE_RENAME"
+elif rdma dev set "$RXE_A" netns "$NS2" name "$RXE_NEW"; then
+ if rdma_dev_exists "$NS2" "$RXE_NEW" &&
+ ! rdma_dev_exists "" "$RXE_A"; then
+ ktap_test_pass "$TEST_COMBINED_MOVE_RENAME"
+ else
+ ktap_test_fail "$TEST_COMBINED_MOVE_RENAME"
+ fi
+else
+ ktap_test_fail "$TEST_COMBINED_MOVE_RENAME"
+fi
+cleanup_devs
+
+if ! setup_devs; then
+ ktap_test_fail "$TEST_SAME_NETNS_DUP_RENAME"
+elif rdma dev set "$RXE_A" name "$RXE_SAME" &&
+ rdma dev set "$RXE_B" name "$RXE_NEW"; then
+ if rdma dev set "$RXE_SAME" name "$RXE_NEW" >/dev/null 2>&1; then
+ ktap_test_fail "$TEST_SAME_NETNS_DUP_RENAME"
+ elif rdma_dev_exists "" "$RXE_SAME" &&
+ rdma_dev_exists "" "$RXE_NEW"; then
+ ktap_test_pass "$TEST_SAME_NETNS_DUP_RENAME"
+ else
+ ktap_test_fail "$TEST_SAME_NETNS_DUP_RENAME"
+ fi
+else
+ ktap_test_fail "$TEST_SAME_NETNS_DUP_RENAME"
+fi
+cleanup_devs
+
+if ! setup_devs; then
+ ktap_test_fail "$TEST_TEARDOWN_RETURN"
+elif ! rdma dev set "$RXE_A" name "$RXE_SAME" ||
+ ! rdma dev set "$RXE_B" netns "$NS2" ||
+ ! rdma_ns "$NS2" dev set "$RXE_B" name "$RXE_SAME" ||
+ ! rdma_dev_exists "$NS2" "$RXE_SAME"; then
+ ktap_test_fail "$TEST_TEARDOWN_RETURN"
+else
+ ip netns del "$NS2"
+ returned=$(wait_rdma_dev_on_netdev "$DUMMY_B")
+ ktap_print_msg "device returned to init_net as '${returned:-<missing>}'"
+ if rdma_dev_exists "" "$RXE_SAME" &&
+ [ -n "$returned" ] &&
+ [ "$returned" != "$RXE_SAME" ] &&
+ [ "${returned#ibdev}" != "$returned" ]; then
+ ktap_test_pass "$TEST_TEARDOWN_RETURN"
+ else
+ ktap_test_fail "$TEST_TEARDOWN_RETURN"
+ fi
+fi
+cleanup_devs
+
+ktap_finished
diff --git a/tools/testing/selftests/rdma/rxe_rping_between_netns.sh b/tools/testing/selftests/rdma/rxe_rping_between_netns.sh
new file mode 100755
index 000000000..e7554fbb8
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_rping_between_netns.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+# Configuration
+NS="test1"
+VETH_A="veth-a"
+VETH_B="veth-b"
+IP_A="1.1.1.1"
+IP_B="1.1.1.2"
+PORT=4791
+
+source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
+
+exec > /dev/null
+
+# --- Cleanup Routine ---
+cleanup() {
+ echo "Cleaning up resources..."
+ rdma link del rxe1 2>/dev/null
+ ip netns exec "$NS" rdma link del rxe0 2>/dev/null
+ ip link delete "$VETH_B" 2>/dev/null
+ ip netns del "$NS" 2>/dev/null
+ modprobe -r rdma_rxe 2>/dev/null
+}
+trap cleanup EXIT
+
+# --- Prerequisite Checks ---
+if [[ $EUID -ne 0 ]]; then
+ echo "This script must be run as root"
+ exit 1
+fi
+
+if ! modinfo rdma_rxe >/dev/null 2>&1; then
+ echo "SKIP: Kernel module 'rdma_rxe' not found." >&2
+ exit $KSFT_SKIP
+fi
+
+modprobe rdma_rxe || { echo "Failed to load rdma_rxe"; exit 1; }
+
+# --- Setup Network Topology ---
+echo "Setting up network namespace and veth pair..."
+ip netns add "$NS"
+ip link add "$VETH_A" type veth peer name "$VETH_B"
+ip link set "$VETH_A" netns "$NS"
+
+# Configure Namespace side (test1)
+ip netns exec "$NS" ip addr add "$IP_A/24" dev "$VETH_A"
+ip netns exec "$NS" ip link set "$VETH_A" up
+ip netns exec "$NS" ip link set lo up
+
+# Configure Host side
+ip addr add "$IP_B/24" dev "$VETH_B"
+ip link set "$VETH_B" up
+
+# --- RXE Link Creation ---
+echo "Creating RDMA links..."
+ip netns exec "$NS" rdma link add rxe0 type rxe netdev "$VETH_A"
+rdma link add rxe1 type rxe netdev "$VETH_B"
+
+# Verify UDP 4791 is listening
+check_port() {
+ local target=$1 # "host" or "ns"
+ if [ "$target" == "ns" ]; then
+ ip netns exec "$NS" ss -Huln sport == :$PORT | grep -q ":$PORT"
+ else
+ ss -Huln sport == :$PORT | grep -q ":$PORT"
+ fi
+}
+
+check_port "ns" || { echo "Error: RXE port not listening in namespace"; exit 1; }
+check_port "host" || { echo "Error: RXE port not listening on host"; exit 1; }
+
+# --- Connectivity Test ---
+echo "Testing connectivity with rping..."
+ping -c 2 -W 1 "$IP_A" > /dev/null || { echo "Ping failed"; exit 1; }
+
+# Start rping server in background
+ip netns exec "$NS" rping -s -a "$IP_A" -v > /dev/null 2>&1 &
+RPING_PID=$!
+sleep 1 # Allow server to bind
+
+# Run rping client
+rping -c -a "$IP_A" -d -v -C 3
+RESULT=$?
+
+kill $RPING_PID 2>/dev/null
+
+if [ $RESULT -eq 0 ]; then
+ echo "SUCCESS: RDMA traffic verified."
+else
+ echo "FAILURE: rping failed."
+ exit 1
+fi
diff --git a/tools/testing/selftests/rdma/rxe_sent_rcvd_bytes.sh b/tools/testing/selftests/rdma/rxe_sent_rcvd_bytes.sh
new file mode 100755
index 000000000..0e4fbfeeb
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_sent_rcvd_bytes.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+# Configuration
+PORT=4791
+MODS=("tun" "rdma_rxe")
+
+exec > /dev/null
+
+# --- Helper: Cleanup Routine ---
+cleanup() {
+ echo "Cleaning up resources..."
+ rdma link del rxe0 2>/dev/null
+ ip link del tun0 2>/dev/null
+ for m in "${MODS[@]}"; do modprobe -r "$m" 2>/dev/null; done
+}
+
+# Ensure cleanup runs on script exit or interrupt
+trap cleanup EXIT
+
+# --- Phase 1: Environment Check ---
+if [[ $EUID -ne 0 ]]; then
+ echo "Error: This script must be run as root."
+ exit 1
+fi
+
+for m in "${MODS[@]}"; do
+ modprobe "$m" || { echo "Error: Failed to load $m"; exit 1; }
+done
+
+# --- Phase 2: Create Interfaces & RXE Links ---
+echo "Creating tun0 (1.1.1.1) and rxe0..."
+ip tuntap add mode tun tun0
+ip addr add 1.1.1.1/24 dev tun0
+ip link set tun0 up
+rdma link add rxe0 type rxe netdev tun0
+
+# Verify port 4791 is listening
+if ! ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT not found after rxe0 creation"
+ exit 1
+fi
+
+orig_s=`cat /sys/class/infiniband/rxe0/ports/1/counters/port_xmit_data`
+orig_r=`cat /sys/class/infiniband/rxe0/ports/1/counters/port_rcv_data`
+
+rping -s -a 1.1.1.1 -C 3 -v &
+sleep 1
+rping -c -a 1.1.1.1 -C 3 -d -v
+
+new_s=`cat /sys/class/infiniband/rxe0/ports/1/counters/port_xmit_data`
+new_r=`cat /sys/class/infiniband/rxe0/ports/1/counters/port_rcv_data`
+
+echo sent $new_s $orig_s
+echo rcvd $new_r $orig_r
+
+result0=$((new_s - orig_s))
+result1=$((new_r - orig_r))
+
+if [ $result0 != $result1 ]; then
+ echo "Error: sent and rcvd bytes different"
+ echo $result0
+ echo $result1
+ exit 1
+fi
+
+echo "Deleting rxe0..."
+rdma link del rxe0
+
+# Port should now be gone
+if ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT still exists after all links deleted"
+ exit 1
+fi
+
+echo "Test passed successfully."
diff --git a/tools/testing/selftests/rdma/rxe_socket_with_netns.sh b/tools/testing/selftests/rdma/rxe_socket_with_netns.sh
new file mode 100755
index 000000000..9478657c0
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_socket_with_netns.sh
@@ -0,0 +1,82 @@
+#!/bin/bash
+
+# Configuration
+PORT=4791
+MODS=("tun" "rdma_rxe")
+
+source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
+
+exec > /dev/null
+
+# --- Helper: Cleanup Routine ---
+cleanup() {
+ echo "Cleaning up resources..."
+ rdma link del rxe1 2>/dev/null
+ rdma link del rxe0 2>/dev/null
+ ip link del tun0 2>/dev/null
+ ip link del tun1 2>/dev/null
+ for m in "${MODS[@]}"; do modprobe -r "$m" 2>/dev/null; done
+}
+
+# Ensure cleanup runs on script exit or interrupt
+trap cleanup EXIT
+
+# --- Phase 1: Environment Check ---
+if [[ $EUID -ne 0 ]]; then
+ echo "Error: This script must be run as root."
+ exit 1
+fi
+
+for m in "${MODS[@]}"; do
+ if ! modinfo "$m" >/dev/null 2>&1; then
+ echo "SKIP: Kernel module '$m' not found." >&2
+ exit $KSFT_SKIP
+ fi
+ modprobe "$m" || { echo "Error: Failed to load $m"; exit 1; }
+done
+
+# --- Phase 2: Create Interfaces & RXE Links ---
+echo "Creating tun0 (1.1.1.1) and rxe0..."
+ip tuntap add mode tun tun0
+ip addr add 1.1.1.1/24 dev tun0
+ip link set tun0 up
+rdma link add rxe0 type rxe netdev tun0
+
+# Verify port 4791 is listening
+if ! ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT not found after rxe0 creation"
+ exit 1
+fi
+
+echo "Creating tun1 (2.2.2.2) and rxe1..."
+ip tuntap add mode tun tun1
+ip addr add 2.2.2.2/24 dev tun1
+ip link set tun1 up
+rdma link add rxe1 type rxe netdev tun1
+
+# Verify port 4791 is still listening
+if ! ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT missing after rxe1 creation"
+ exit 1
+fi
+
+# --- Phase 3: Targeted Deletion ---
+echo "Deleting rxe1..."
+rdma link del rxe1
+
+# Port should still be active because rxe0 is still alive
+if ! ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT closed prematurely"
+ exit 1
+fi
+
+echo "Deleting rxe0..."
+rdma link del rxe0
+
+# Port should now be gone
+if ss -Huln sport = :$PORT | grep -q ":$PORT"; then
+ echo "Error: UDP port $PORT still exists after all links deleted"
+ exit 1
+fi
+
+echo "Test passed successfully."
diff --git a/tools/testing/selftests/rdma/rxe_test_NETDEV_UNREGISTER.sh b/tools/testing/selftests/rdma/rxe_test_NETDEV_UNREGISTER.sh
new file mode 100755
index 000000000..8c18cea75
--- /dev/null
+++ b/tools/testing/selftests/rdma/rxe_test_NETDEV_UNREGISTER.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# Configuration
+DEV_NAME="tun0"
+RXE_NAME="rxe0"
+RDMA_PORT=4791
+
+source "$(dirname "$0")/../kselftest/ktap_helpers.sh"
+
+exec > /dev/null
+
+# --- Cleanup Routine ---
+# Ensures environment is clean even if the script hits an error
+cleanup() {
+ echo "Performing cleanup..."
+ rdma link del $RXE_NAME 2>/dev/null
+ ip link del $DEV_NAME 2>/dev/null
+ modprobe -r rdma_rxe 2>/dev/null
+}
+trap cleanup EXIT
+
+# 1. Dependency Check
+if ! modinfo rdma_rxe >/dev/null 2>&1; then
+ echo "SKIP: rdma_rxe module not found." >&2
+ exit $KSFT_SKIP
+fi
+
+modprobe rdma_rxe
+
+# 2. Setup TUN Device
+echo "Creating $DEV_NAME..."
+ip tuntap add mode tun "$DEV_NAME"
+ip addr add 1.1.1.1/24 dev "$DEV_NAME"
+ip link set "$DEV_NAME" up
+
+# 3. Attach RXE Link
+echo "Attaching RXE link $RXE_NAME to $DEV_NAME..."
+rdma link add "$RXE_NAME" type rxe netdev "$DEV_NAME"
+
+# 4. Verification: Port Check
+# Use -H (no header) and -q (quiet) for cleaner scripting logic
+if ! ss -Huln sport == :$RDMA_PORT | grep -q ":$RDMA_PORT"; then
+ echo "Error: UDP port $RDMA_PORT is not listening."
+ exit 1
+fi
+echo "Verified: RXE is listening on UDP $RDMA_PORT."
+
+# 5. Trigger NETDEV_UNREGISTER
+# We delete the underlying device without deleting the RDMA link first.
+echo "Triggering NETDEV_UNREGISTER by deleting $DEV_NAME..."
+ip link del "$DEV_NAME"
+
+# 6. Final Verification
+# The RXE link and the UDP port should be automatically cleaned up by the kernel.
+if rdma link show "$RXE_NAME" 2>/dev/null; then
+ echo "Error: $RXE_NAME still exists after netdev removal."
+ exit 1
+fi
+
+if ss -Huln sport == :$RDMA_PORT | grep -q ":$RDMA_PORT"; then
+ echo "Error: UDP port $RDMA_PORT still listening after netdev removal."
+ exit 1
+fi
+
+echo "Success: NETDEV_UNREGISTER handled correctly."