xref: /linux/tools/testing/selftests/net/ipvtap_test.sh (revision 0a80e38d0fe1fe7b59c1e93ad908c4148a15926a)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Simple tests for ipvtap
5
6
7#
8# The testing environment looks this way:
9#
10# |------HNS-------|     |------PHY-------|
11# |      veth<----------------->veth      |
12# |------|--|------|     |----------------|
13#        |  |
14#        |  |            |-----TST0-------|
15#        |  |------------|----ipvlan      |
16#        |               |----------------|
17#        |
18#        |               |-----TST1-------|
19#        |---------------|----ipvlan      |
20#                        |----------------|
21#
22
23ALL_TESTS="
24	test_ip_set
25"
26
27source lib.sh
28
29DEBUG=0
30
31VETH_HOST=vethtst.h
32VETH_PHY=vethtst.p
33
34NS_COUNT=32
35IP_ITERATIONS=1024
36IPSET_TIMEOUT="60s"
37
38ns_run() {
39	ns=$1
40	shift
41	if [[ "$ns" == "global" ]]; then
42		"$@" >/dev/null
43	else
44		ip netns exec "$ns" "$@" >/dev/null
45	fi
46}
47
48test_ip_setup_env() {
49	setup_ns NS_PHY
50	setup_ns HST_NS
51
52	# setup simulated other-host (phy) and host itself
53	ns_run "$HST_NS" ip link add $VETH_HOST type veth peer name $VETH_PHY \
54		netns "$NS_PHY" >/dev/null
55	ns_run "$HST_NS" ip link set $VETH_HOST up
56	ns_run "$NS_PHY" ip link set $VETH_PHY up
57
58	for ((i=0; i<NS_COUNT; i++)); do
59		setup_ns ipvlan_ns_$i
60		ns="ipvlan_ns_$i"
61		if [ "$DEBUG" = "1" ]; then
62			echo "created NS ${!ns}"
63		fi
64		if ! ns_run "$HST_NS" ip link add netns ${!ns} ipvlan0 \
65		    link $VETH_HOST \
66		    type ipvtap mode l2 bridge; then
67			exit_error "FAIL: Failed to configure ipvlan link."
68		fi
69	done
70}
71
72test_ip_cleanup_env() {
73	ns_run "$HST_NS" ip link del $VETH_HOST
74	cleanup_all_ns
75}
76
77exit_error() {
78	echo "$1"
79	exit $ksft_fail
80}
81
82rnd() {
83	echo $(( RANDOM % 32 + 16 ))
84}
85
86test_ip_set_thread() {
87	# Here we are trying to create some IP conflicts between namespaces.
88	# If just add/remove IP, nothing interesting will happen.
89	# But if add random IP and then remove random IP,
90	# eventually conflicts start to apear.
91	ip link set ipvlan0 up
92	for ((i=0; i<IP_ITERATIONS; i++)); do
93		v=$(rnd)
94		ip a a "172.25.0.$v/24" dev ipvlan0 2>/dev/null
95		ip a a "fc00::$v/64" dev ipvlan0 2>/dev/null
96		v=$(rnd)
97		ip a d "172.25.0.$v/24" dev ipvlan0 2>/dev/null
98		ip a d "fc00::$v/64" dev ipvlan0 2>/dev/null
99	done
100}
101
102test_ip_set() {
103	RET=0
104
105	trap test_ip_cleanup_env EXIT
106
107	test_ip_setup_env
108
109	declare -A ns_pids
110	for ((i=0; i<NS_COUNT; i++)); do
111		ns="ipvlan_ns_$i"
112		ns_run ${!ns} timeout "$IPSET_TIMEOUT" \
113			bash -c "$0 test_ip_set_thread"&
114		ns_pids[$i]=$!
115	done
116
117	for ((i=0; i<NS_COUNT; i++)); do
118		wait "${ns_pids[$i]}"
119	done
120
121	declare -A all_ips
122	for ((i=0; i<NS_COUNT; i++)); do
123		ns="ipvlan_ns_$i"
124		ip_output=$(ip netns exec ${!ns} ip a l dev ipvlan0 | grep inet)
125		while IFS= read -r nsip_out; do
126			if [[ -z $nsip_out ]]; then
127				continue;
128			fi
129			nsip=$(awk '{print $2}' <<< "$nsip_out")
130			if [[ -v all_ips[$nsip] ]]; then
131				RET=$ksft_fail
132				log_test "conflict for $nsip"
133				return "$RET"
134			else
135				all_ips[$nsip]=$i
136			fi
137		done <<< "$ip_output"
138	done
139
140	if [ "$DEBUG" = "1" ]; then
141		for key in "${!all_ips[@]}"; do
142			echo "$key: ${all_ips[$key]}"
143		done
144	fi
145
146	trap - EXIT
147	test_ip_cleanup_env
148
149	log_test "test multithreaded ip set"
150}
151
152if [[ "$1" == "-d" ]]; then
153	DEBUG=1
154	shift
155fi
156
157if [[ "$1" == "-t" ]]; then
158	shift
159	TESTS="$*"
160fi
161
162if [[ "$1" == "test_ip_set_thread" ]]; then
163	test_ip_set_thread
164else
165	require_command ip
166
167	tests_run
168fi
169