xref: /linux/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# These tests verify that teamd is able to enable and disable ports via the
5# active backup runner.
6#
7# Topology:
8#
9#  +-------------------------+  NS1
10#  |        test_team1       |
11#  |            +            |
12#  |      eth0  |  eth1      |
13#  |        +---+---+        |
14#  |        |       |        |
15#  +-------------------------+
16#           |       |
17#  +-------------------------+  NS2
18#  |        |       |        |
19#  |        +-------+        |
20#  |      eth0  |  eth1      |
21#  |            +            |
22#  |        test_team2       |
23#  +-------------------------+
24
25export ALL_TESTS="teamd_test_active_backup"
26
27test_dir="$(dirname "$0")"
28# shellcheck disable=SC1091
29source "${test_dir}/../../../net/lib.sh"
30# shellcheck disable=SC1091
31source "${test_dir}/team_lib.sh"
32
33NS1=""
34NS2=""
35export NODAD="nodad"
36PREFIX_LENGTH="64"
37NS1_IP="fd00::1"
38NS2_IP="fd00::2"
39NS1_IP4="192.168.0.1"
40NS2_IP4="192.168.0.2"
41NS1_TEAMD_CONF=""
42NS2_TEAMD_CONF=""
43NS1_TEAMD_PID=""
44NS2_TEAMD_PID=""
45
46while getopts "4" opt; do
47	case $opt in
48		4)
49			echo "IPv4 mode selected."
50			export NODAD=
51			PREFIX_LENGTH="24"
52			NS1_IP="${NS1_IP4}"
53			NS2_IP="${NS2_IP4}"
54			;;
55		\?)
56			echo "Invalid option: -${OPTARG}" >&2
57			exit 1
58			;;
59	esac
60done
61
62teamd_config_create()
63{
64	local runner=$1
65	local dev=$2
66	local conf
67
68	conf=$(mktemp)
69
70	cat > "${conf}" <<-EOF
71	{
72		"device": "${dev}",
73		"runner": {"name": "${runner}"},
74		"ports": {
75			"eth0": {},
76			"eth1": {}
77		}
78	}
79	EOF
80	echo "${conf}"
81}
82
83# Create the network namespaces, veth pair, and team devices in the specified
84# runner.
85# Globals:
86#   RET - Used by test infra, set by `check_err` functions.
87# Arguments:
88#   runner - The Teamd runner to use for the Team devices.
89environment_create()
90{
91	local runner=$1
92
93	echo "Setting up two-link aggregation for runner ${runner}"
94	echo "Teamd version is: $(teamd --version)"
95	trap environment_destroy EXIT
96
97	setup_ns ns1 ns2
98	NS1="${NS_LIST[0]}"
99	NS2="${NS_LIST[1]}"
100
101	for link in $(seq 0 1); do
102		ip -n "${NS1}" link add "eth${link}" type veth peer name \
103				"eth${link}" netns "${NS2}"
104		check_err $? "Failed to create veth pair"
105	done
106
107	NS1_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team1")
108	NS2_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team2")
109	echo "Conf files are ${NS1_TEAMD_CONF} and ${NS2_TEAMD_CONF}"
110
111	ip netns exec "${NS1}" teamd -d -f "${NS1_TEAMD_CONF}"
112	check_err $? "Failed to create team device in ${NS1}"
113	NS1_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS1_TEAMD_CONF}")
114
115	ip netns exec "${NS2}" teamd -d -f "${NS2_TEAMD_CONF}"
116	check_err $? "Failed to create team device in ${NS2}"
117	NS2_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS2_TEAMD_CONF}")
118
119	echo "Created team devices"
120	echo "Teamd PIDs are ${NS1_TEAMD_PID} and ${NS2_TEAMD_PID}"
121
122	ip -n "${NS1}" link set test_team1 up
123	check_err $? "Failed to set test_team1 up in ${NS1}"
124	ip -n "${NS2}" link set test_team2 up
125	check_err $? "Failed to set test_team2 up in ${NS2}"
126
127	ip -n "${NS1}" addr add "${NS1_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \
128			test_team1
129	check_err $? "Failed to add address to team device in ${NS1}"
130	ip -n "${NS2}" addr add "${NS2_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \
131			test_team2
132	check_err $? "Failed to add address to team device in ${NS2}"
133
134	slowwait 2 timeout 0.5 ip netns exec "${NS1}" ping -W 1 -c 1 "${NS2_IP}"
135}
136
137# Tear down the environment: kill teamd and delete network namespaces.
138environment_destroy()
139{
140	echo "Tearing down two-link aggregation"
141
142	rm "${NS1_TEAMD_CONF}"
143	rm "${NS2_TEAMD_CONF}"
144
145	# First, try graceful teamd teardown.
146	ip netns exec "${NS1}" teamd -k -t test_team1
147	ip netns exec "${NS2}" teamd -k -t test_team2
148
149	# If teamd can't be killed gracefully, then sigkill.
150	if kill -0 "${NS1_TEAMD_PID}" 2>/dev/null; then
151		echo "Sending sigkill to teamd for test_team1"
152		kill -9 "${NS1_TEAMD_PID}"
153		rm -f /var/run/teamd/test_team1.{pid,sock}
154	fi
155	if kill -0 "${NS2_TEAMD_PID}" 2>/dev/null; then
156		echo "Sending sigkill to teamd for test_team2"
157		kill -9 "${NS2_TEAMD_PID}"
158		rm -f /var/run/teamd/test_team2.{pid,sock}
159	fi
160	cleanup_all_ns
161}
162
163# Change the active port for an active-backup mode team.
164# Arguments:
165#   namespace - The network namespace that the team is in.
166#   team - The name of the team.
167#   active_port - The port to make active.
168set_active_port()
169{
170	local namespace=$1
171	local team=$2
172	local active_port=$3
173
174	ip netns exec "${namespace}" teamdctl "${team}" state item set \
175			runner.active_port "${active_port}"
176	slowwait 2 bash -c "ip netns exec ${namespace} teamdctl ${team} state \
177			item get runner.active_port | grep -q ${active_port}"
178}
179
180# Wait for an interface to stop receiving traffic. If it keeps receiving traffic
181# for the duration of the timeout, then return an error.
182# Arguments:
183#   - namespace - The network namespace that the interface is in.
184#   - interface - The name of the interface.
185wait_to_stop_receiving()
186{
187	local namespace=$1
188	local interface=$2
189
190	echo "Waiting for ${interface} in ${namespace} to stop receiving"
191	slowwait 10 check_no_traffic "${interface}" "${NS2_IP}" \
192			"${namespace}"
193}
194
195# Test that active backup runner can change active ports.
196# Globals:
197#   RET - Used by test infra, set by `check_err` functions.
198teamd_test_active_backup()
199{
200	export RET=0
201
202	start_listening_and_sending
203
204	### Scenario 1: Don't manually set active port, just make sure team
205	# works.
206	save_tcpdump_outputs "${NS2}" test_team2
207	did_interface_receive test_team2 "${NS2_IP}"
208	check_err $? "Traffic did not reach team interface in NS2."
209	clear_tcpdump_outputs test_team2
210
211	### Scenario 2: Choose active port.
212	set_active_port "${NS1}" test_team1 eth1
213	set_active_port "${NS2}" test_team2 eth1
214
215	wait_to_stop_receiving "${NS2}" eth0
216	save_tcpdump_outputs "${NS2}" eth0 eth1
217	did_interface_receive eth0 "${NS2_IP}"
218	check_fail $? "eth0 IS transmitting when inactive"
219	did_interface_receive eth1 "${NS2_IP}"
220	check_err $? "eth1 not transmitting when active"
221	clear_tcpdump_outputs eth0 eth1
222
223	### Scenario 3: Change active port.
224	set_active_port "${NS1}" test_team1 eth0
225	set_active_port "${NS2}" test_team2 eth0
226
227	wait_to_stop_receiving "${NS2}" eth1
228	save_tcpdump_outputs "${NS2}" eth0 eth1
229	did_interface_receive eth0 "${NS2_IP}"
230	check_err $? "eth0 not transmitting when active"
231	did_interface_receive eth1 "${NS2_IP}"
232	check_fail $? "eth1 IS transmitting when inactive"
233	clear_tcpdump_outputs eth0 eth1
234
235	log_test "teamd active backup runner test"
236
237	stop_sending_and_listening
238}
239
240require_command teamd
241require_command teamdctl
242require_command iperf3
243require_command tcpdump
244environment_create activebackup
245tests_run
246exit "${EXIT_STATUS}"
247