xref: /linux/tools/testing/selftests/drivers/net/bonding/bond_options.sh (revision cfaaa7d010d1fc58f9717fcc8591201e741d2d49)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test bonding options with mode 1,5,6
5
6ALL_TESTS="
7	prio
8	arp_validate
9	num_grat_arp
10"
11
12lib_dir=$(dirname "$0")
13source ${lib_dir}/bond_topo_3d1c.sh
14c_maddr="33:33:00:00:00:10"
15g_maddr="33:33:00:00:02:54"
16
17skip_prio()
18{
19	local skip=1
20
21	# check if iproute support prio option
22	ip -n ${s_ns} link set eth0 type bond_slave prio 10
23	[[ $? -ne 0 ]] && skip=0
24
25	# check if kernel support prio option
26	ip -n ${s_ns} -d link show eth0 | grep -q "prio 10"
27	[[ $? -ne 0 ]] && skip=0
28
29	return $skip
30}
31
32skip_ns()
33{
34	local skip=1
35
36	# check if iproute support ns_ip6_target option
37	ip -n ${s_ns} link add bond1 type bond ns_ip6_target ${g_ip6}
38	[[ $? -ne 0 ]] && skip=0
39
40	# check if kernel support ns_ip6_target option
41	ip -n ${s_ns} -d link show bond1 | grep -q "ns_ip6_target ${g_ip6}"
42	[[ $? -ne 0 ]] && skip=0
43
44	ip -n ${s_ns} link del bond1
45
46	return $skip
47}
48
49active_slave=""
50active_slave_changed()
51{
52	local old_active_slave=$1
53	local new_active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" \
54				".[].linkinfo.info_data.active_slave")
55	[ "$new_active_slave" != "$old_active_slave" -a "$new_active_slave" != "null" ]
56}
57
58check_active_slave()
59{
60	local target_active_slave=$1
61	slowwait 5 active_slave_changed $active_slave
62	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
63	test "$active_slave" = "$target_active_slave"
64	check_err $? "Current active slave is $active_slave but not $target_active_slave"
65}
66
67# Test bonding prio option
68prio_test()
69{
70	local param="$1"
71	RET=0
72
73	# create bond
74	bond_reset "${param}"
75	# set active_slave to primary eth1 specifically
76	ip -n ${s_ns} link set bond0 type bond active_slave eth1
77
78	# check bonding member prio value
79	ip -n ${s_ns} link set eth0 type bond_slave prio 0
80	ip -n ${s_ns} link set eth1 type bond_slave prio 10
81	ip -n ${s_ns} link set eth2 type bond_slave prio 11
82	cmd_jq "ip -n ${s_ns} -d -j link show eth0" \
83		".[].linkinfo.info_slave_data | select (.prio == 0)" "-e" &> /dev/null
84	check_err $? "eth0 prio is not 0"
85	cmd_jq "ip -n ${s_ns} -d -j link show eth1" \
86		".[].linkinfo.info_slave_data | select (.prio == 10)" "-e" &> /dev/null
87	check_err $? "eth1 prio is not 10"
88	cmd_jq "ip -n ${s_ns} -d -j link show eth2" \
89		".[].linkinfo.info_slave_data | select (.prio == 11)" "-e" &> /dev/null
90	check_err $? "eth2 prio is not 11"
91
92	bond_check_connection "setup"
93
94	# active slave should be the primary slave
95	check_active_slave eth1
96
97	# active slave should be the higher prio slave
98	ip -n ${s_ns} link set $active_slave down
99	check_active_slave eth2
100	bond_check_connection "fail over"
101
102	# when only 1 slave is up
103	ip -n ${s_ns} link set $active_slave down
104	check_active_slave eth0
105	bond_check_connection "only 1 slave up"
106
107	# when a higher prio slave change to up
108	ip -n ${s_ns} link set eth2 up
109	bond_check_connection "higher prio slave up"
110	case $primary_reselect in
111		"0")
112			check_active_slave "eth2"
113			;;
114		"1")
115			check_active_slave "eth0"
116			;;
117		"2")
118			check_active_slave "eth0"
119			;;
120	esac
121	local pre_active_slave=$active_slave
122
123	# when the primary slave change to up
124	ip -n ${s_ns} link set eth1 up
125	bond_check_connection "primary slave up"
126	case $primary_reselect in
127		"0")
128			check_active_slave "eth1"
129			;;
130		"1")
131			check_active_slave "$pre_active_slave"
132			;;
133		"2")
134			check_active_slave "$pre_active_slave"
135			ip -n ${s_ns} link set $active_slave down
136			bond_check_connection "pre_active slave down"
137			check_active_slave "eth1"
138			;;
139	esac
140
141	# Test changing bond slave prio
142	if [[ "$primary_reselect" == "0" ]];then
143		ip -n ${s_ns} link set eth0 type bond_slave prio 1000000
144		ip -n ${s_ns} link set eth1 type bond_slave prio 0
145		ip -n ${s_ns} link set eth2 type bond_slave prio -50
146		ip -n ${s_ns} -d link show eth0 | grep -q 'prio 1000000'
147		check_err $? "eth0 prio is not 1000000"
148		ip -n ${s_ns} -d link show eth1 | grep -q 'prio 0'
149		check_err $? "eth1 prio is not 0"
150		ip -n ${s_ns} -d link show eth2 | grep -q 'prio -50'
151		check_err $? "eth3 prio is not -50"
152		check_active_slave "eth1"
153
154		ip -n ${s_ns} link set $active_slave down
155		check_active_slave "eth0"
156		bond_check_connection "change slave prio"
157	fi
158}
159
160prio_miimon()
161{
162	local primary_reselect
163	local mode=$1
164
165	for primary_reselect in 0 1 2; do
166		prio_test "mode $mode miimon 100 primary eth1 primary_reselect $primary_reselect"
167		log_test "prio" "$mode miimon primary_reselect $primary_reselect"
168	done
169}
170
171prio_arp()
172{
173	local primary_reselect
174	local mode=$1
175
176	for primary_reselect in 0 1 2; do
177		prio_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} primary eth1 primary_reselect $primary_reselect"
178		log_test "prio" "$mode arp_ip_target primary_reselect $primary_reselect"
179	done
180}
181
182prio_ns()
183{
184	local primary_reselect
185	local mode=$1
186
187	if skip_ns; then
188		log_test_skip "prio ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
189		return 0
190	fi
191
192	for primary_reselect in 0 1 2; do
193		prio_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} primary eth1 primary_reselect $primary_reselect"
194		log_test "prio" "$mode ns_ip6_target primary_reselect $primary_reselect"
195	done
196}
197
198prio()
199{
200	local mode modes="active-backup balance-tlb balance-alb"
201
202	if skip_prio; then
203		log_test_skip "prio" "Current iproute or kernel doesn't support bond option 'prio'."
204		return 0
205	fi
206
207	for mode in $modes; do
208		prio_miimon $mode
209	done
210	prio_arp "active-backup"
211	prio_ns "active-backup"
212}
213
214wait_mii_up()
215{
216	for i in $(seq 0 2); do
217		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
218		[ ${mii_status} != "UP" ] && return 1
219	done
220	return 0
221}
222
223arp_validate_test()
224{
225	local param="$1"
226	RET=0
227
228	# create bond
229	bond_reset "${param}"
230
231	bond_check_connection
232	[ $RET -ne 0 ] && log_test "arp_validate" "$retmsg"
233
234	# wait for a while to make sure the mii status stable
235	slowwait 5 wait_mii_up
236	for i in $(seq 0 2); do
237		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
238		if [ ${mii_status} != "UP" ]; then
239			RET=1
240			log_test "arp_validate" "interface eth$i mii_status $mii_status"
241		fi
242	done
243}
244
245# Testing correct multicast groups are added to slaves for ns targets
246arp_validate_mcast()
247{
248	RET=0
249	local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
250	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
251
252	for i in $(seq 0 2); do
253		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
254
255		# arp_valid == 0 or active_slave should not join any maddrs
256		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
257			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
258			RET=1
259			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
260		# arp_valid != 0 and backup_slave should join both maddrs
261		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
262		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
263		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
264			RET=1
265			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
266		fi
267	done
268
269	# Do failover
270	ip -n ${s_ns} link set ${active_slave} down
271	# wait for active link change
272	slowwait 2 active_slave_changed $active_slave
273	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
274
275	for i in $(seq 0 2); do
276		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
277
278		# arp_valid == 0 or active_slave should not join any maddrs
279		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
280			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
281			RET=1
282			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
283		# arp_valid != 0 and backup_slave should join both maddrs
284		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
285		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
286		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
287			RET=1
288			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
289		fi
290	done
291}
292
293arp_validate_arp()
294{
295	local mode=$1
296	local val
297	for val in $(seq 0 6); do
298		arp_validate_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} arp_validate $val"
299		log_test "arp_validate" "$mode arp_ip_target arp_validate $val"
300	done
301}
302
303arp_validate_ns()
304{
305	local mode=$1
306	local val
307
308	if skip_ns; then
309		log_test_skip "arp_validate ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
310		return 0
311	fi
312
313	for val in $(seq 0 6); do
314		arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
315		log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
316		arp_validate_mcast
317		log_test "arp_validate" "join mcast group"
318	done
319}
320
321arp_validate()
322{
323	arp_validate_arp "active-backup"
324	arp_validate_ns "active-backup"
325}
326
327garp_test()
328{
329	local param="$1"
330	local active_slave exp_num real_num i
331	RET=0
332
333	# create bond
334	bond_reset "${param}"
335
336	bond_check_connection
337	[ $RET -ne 0 ] && log_test "num_grat_arp" "$retmsg"
338
339
340	# Add tc rules to count GARP number
341	for i in $(seq 0 2); do
342		tc -n ${g_ns} filter add dev s$i ingress protocol arp pref 1 handle 101 \
343			flower skip_hw arp_op request arp_sip ${s_ip4} arp_tip ${s_ip4} action pass
344	done
345
346	# Do failover
347	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
348	ip -n ${s_ns} link set ${active_slave} down
349
350	# wait for active link change
351	slowwait 2 active_slave_changed $active_slave
352
353	exp_num=$(echo "${param}" | cut -f6 -d ' ')
354	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
355	slowwait_for_counter $((exp_num + 5)) $exp_num \
356		tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}"
357
358	# check result
359	real_num=$(tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}")
360	if [ "${real_num}" -ne "${exp_num}" ]; then
361		echo "$real_num garp packets sent on active slave ${active_slave}"
362		RET=1
363	fi
364
365	for i in $(seq 0 2); do
366		tc -n ${g_ns} filter del dev s$i ingress
367	done
368}
369
370num_grat_arp()
371{
372	local val
373	for val in 10 20 30; do
374		garp_test "mode active-backup miimon 10 num_grat_arp $val peer_notify_delay 100"
375		log_test "num_grat_arp" "active-backup miimon num_grat_arp $val"
376	done
377}
378
379trap cleanup EXIT
380
381setup_prepare
382setup_wait
383tests_run
384
385exit $EXIT_STATUS
386