]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests: net: simple selftest for ipvtap
authorDmitry Skorodumov <dskr99@gmail.com>
Mon, 12 Jan 2026 14:24:07 +0000 (17:24 +0300)
committerJakub Kicinski <kuba@kernel.org>
Mon, 19 Jan 2026 18:03:31 +0000 (10:03 -0800)
This is a simple ipvtap test to test handling
IP-address add/remove on ipvlan interface.

It creates a veth-interface and then creates several
network-namespace with ipvlan0 interface in it linked to veth.

Then it starts to add/remove addresses on ipvlan0 interfaces
in several threads.

At finish, it checks that there is no duplicated addresses.

Signed-off-by: Dmitry Skorodumov <skorodumov.dmitry@huawei.com>
Link: https://patch.msgid.link/20260112142417.4039566-3-skorodumov.dmitry@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/config
tools/testing/selftests/net/ipvtap_test.sh [new file with mode: 0755]

index b66ba04f19d9a1753579c36b31c5619c8008df91..45c4ea381bc360630d21fd0a15243e6810530321 100644 (file)
@@ -48,6 +48,7 @@ TEST_PROGS := \
        ipv6_flowlabel.sh \
        ipv6_force_forwarding.sh \
        ipv6_route_update_soft_lockup.sh \
+       ipvtap_test.sh \
        l2_tos_ttl_inherit.sh \
        l2tp.sh \
        link_netns.py \
index 1e1f253118f562de7f1a41dc5e66730e2402b2e6..b84362b9b50825da4414871d715ca191ca3cbe6f 100644 (file)
@@ -48,6 +48,7 @@ CONFIG_IPV6_SEG6_LWTUNNEL=y
 CONFIG_IPV6_SIT=y
 CONFIG_IPV6_VTI=y
 CONFIG_IPVLAN=m
+CONFIG_IPVTAP=m
 CONFIG_KALLSYMS=y
 CONFIG_L2TP=m
 CONFIG_L2TP_ETH=m
@@ -116,6 +117,7 @@ CONFIG_PROC_SYSCTL=y
 CONFIG_PSAMPLE=m
 CONFIG_RPS=y
 CONFIG_SYSFS=y
+CONFIG_TAP=m
 CONFIG_TCP_MD5SIG=y
 CONFIG_TEST_BLACKHOLE_DEV=m
 CONFIG_TEST_BPF=m
diff --git a/tools/testing/selftests/net/ipvtap_test.sh b/tools/testing/selftests/net/ipvtap_test.sh
new file mode 100755 (executable)
index 0000000..354ca7c
--- /dev/null
@@ -0,0 +1,168 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Simple tests for ipvtap
+
+
+#
+# The testing environment looks this way:
+#
+# |------HNS-------|     |------PHY-------|
+# |      veth<----------------->veth      |
+# |------|--|------|     |----------------|
+#        |  |
+#        |  |            |-----TST0-------|
+#        |  |------------|----ipvlan      |
+#        |               |----------------|
+#        |
+#        |               |-----TST1-------|
+#        |---------------|----ipvlan      |
+#                        |----------------|
+#
+
+ALL_TESTS="
+       test_ip_set
+"
+
+source lib.sh
+
+DEBUG=0
+
+VETH_HOST=vethtst.h
+VETH_PHY=vethtst.p
+
+NS_COUNT=32
+IP_ITERATIONS=1024
+IPSET_TIMEOUT="60s"
+
+ns_run() {
+       ns=$1
+       shift
+       if [[ "$ns" == "global" ]]; then
+               "$@" >/dev/null
+       else
+               ip netns exec "$ns" "$@" >/dev/null
+       fi
+}
+
+test_ip_setup_env() {
+       setup_ns NS_PHY
+       setup_ns HST_NS
+
+       # setup simulated other-host (phy) and host itself
+       ns_run "$HST_NS" ip link add $VETH_HOST type veth peer name $VETH_PHY \
+               netns "$NS_PHY" >/dev/null
+       ns_run "$HST_NS" ip link set $VETH_HOST up
+       ns_run "$NS_PHY" ip link set $VETH_PHY up
+
+       for ((i=0; i<NS_COUNT; i++)); do
+               setup_ns ipvlan_ns_$i
+               ns="ipvlan_ns_$i"
+               if [ "$DEBUG" = "1" ]; then
+                       echo "created NS ${!ns}"
+               fi
+               if ! ns_run "$HST_NS" ip link add netns ${!ns} ipvlan0 \
+                   link $VETH_HOST \
+                   type ipvtap mode l2 bridge; then
+                       exit_error "FAIL: Failed to configure ipvlan link."
+               fi
+       done
+}
+
+test_ip_cleanup_env() {
+       ns_run "$HST_NS" ip link del $VETH_HOST
+       cleanup_all_ns
+}
+
+exit_error() {
+       echo "$1"
+       exit $ksft_fail
+}
+
+rnd() {
+       echo $(( RANDOM % 32 + 16 ))
+}
+
+test_ip_set_thread() {
+       # Here we are trying to create some IP conflicts between namespaces.
+       # If just add/remove IP, nothing interesting will happen.
+       # But if add random IP and then remove random IP,
+       # eventually conflicts start to apear.
+       ip link set ipvlan0 up
+       for ((i=0; i<IP_ITERATIONS; i++)); do
+               v=$(rnd)
+               ip a a "172.25.0.$v/24" dev ipvlan0 2>/dev/null
+               ip a a "fc00::$v/64" dev ipvlan0 2>/dev/null
+               v=$(rnd)
+               ip a d "172.25.0.$v/24" dev ipvlan0 2>/dev/null
+               ip a d "fc00::$v/64" dev ipvlan0 2>/dev/null
+       done
+}
+
+test_ip_set() {
+       RET=0
+
+       trap test_ip_cleanup_env EXIT
+
+       test_ip_setup_env
+
+       declare -A ns_pids
+       for ((i=0; i<NS_COUNT; i++)); do
+               ns="ipvlan_ns_$i"
+               ns_run ${!ns} timeout "$IPSET_TIMEOUT" \
+                       bash -c "$0 test_ip_set_thread"&
+               ns_pids[$i]=$!
+       done
+
+       for ((i=0; i<NS_COUNT; i++)); do
+               wait "${ns_pids[$i]}"
+       done
+
+       declare -A all_ips
+       for ((i=0; i<NS_COUNT; i++)); do
+               ns="ipvlan_ns_$i"
+               ip_output=$(ip netns exec ${!ns} ip a l dev ipvlan0 | grep inet)
+               while IFS= read -r nsip_out; do
+                       if [[ -z $nsip_out ]]; then
+                               continue;
+                       fi
+                       nsip=$(awk '{print $2}' <<< "$nsip_out")
+                       if [[ -v all_ips[$nsip] ]]; then
+                               RET=$ksft_fail
+                               log_test "conflict for $nsip"
+                               return "$RET"
+                       else
+                               all_ips[$nsip]=$i
+                       fi
+               done <<< "$ip_output"
+       done
+
+       if [ "$DEBUG" = "1" ]; then
+               for key in "${!all_ips[@]}"; do
+                       echo "$key: ${all_ips[$key]}"
+               done
+       fi
+
+       trap - EXIT
+       test_ip_cleanup_env
+
+       log_test "test multithreaded ip set"
+}
+
+if [[ "$1" == "-d" ]]; then
+       DEBUG=1
+       shift
+fi
+
+if [[ "$1" == "-t" ]]; then
+       shift
+       TESTS="$*"
+fi
+
+if [[ "$1" == "test_ip_set_thread" ]]; then
+       test_ip_set_thread
+else
+       require_command ip
+
+       tests_run
+fi