xref: /linux/tools/testing/selftests/drivers/net/bonding/bond_options.sh (revision 2293c57484ae64c9a3c847c8807db8c26a3a4d41)
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	fail_over_mac
11"
12
13lib_dir=$(dirname "$0")
14source ${lib_dir}/bond_topo_3d1c.sh
15c_maddr="33:33:ff:00:00:10"
16g_maddr="33:33:ff:00:02:54"
17
18skip_prio()
19{
20	local skip=1
21
22	# check if iproute support prio option
23	ip -n ${s_ns} link set eth0 type bond_slave prio 10
24	[[ $? -ne 0 ]] && skip=0
25
26	# check if kernel support prio option
27	ip -n ${s_ns} -d link show eth0 | grep -q "prio 10"
28	[[ $? -ne 0 ]] && skip=0
29
30	return $skip
31}
32
33skip_ns()
34{
35	local skip=1
36
37	# check if iproute support ns_ip6_target option
38	ip -n ${s_ns} link add bond1 type bond ns_ip6_target ${g_ip6}
39	[[ $? -ne 0 ]] && skip=0
40
41	# check if kernel support ns_ip6_target option
42	ip -n ${s_ns} -d link show bond1 | grep -q "ns_ip6_target ${g_ip6}"
43	[[ $? -ne 0 ]] && skip=0
44
45	ip -n ${s_ns} link del bond1
46
47	return $skip
48}
49
50active_slave=""
51active_slave_changed()
52{
53	local old_active_slave=$1
54	local new_active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" \
55				".[].linkinfo.info_data.active_slave")
56	[ "$new_active_slave" != "$old_active_slave" -a "$new_active_slave" != "null" ]
57}
58
59check_active_slave()
60{
61	local target_active_slave=$1
62	slowwait 5 active_slave_changed $active_slave
63	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
64	test "$active_slave" = "$target_active_slave"
65	check_err $? "Current active slave is $active_slave but not $target_active_slave"
66}
67
68# Test bonding prio option
69prio_test()
70{
71	local param="$1"
72	RET=0
73
74	# create bond
75	bond_reset "${param}"
76	# set active_slave to primary eth1 specifically
77	ip -n ${s_ns} link set bond0 type bond active_slave eth1
78
79	# check bonding member prio value
80	ip -n ${s_ns} link set eth0 type bond_slave prio 0
81	ip -n ${s_ns} link set eth1 type bond_slave prio 10
82	ip -n ${s_ns} link set eth2 type bond_slave prio 11
83	cmd_jq "ip -n ${s_ns} -d -j link show eth0" \
84		".[].linkinfo.info_slave_data | select (.prio == 0)" "-e" &> /dev/null
85	check_err $? "eth0 prio is not 0"
86	cmd_jq "ip -n ${s_ns} -d -j link show eth1" \
87		".[].linkinfo.info_slave_data | select (.prio == 10)" "-e" &> /dev/null
88	check_err $? "eth1 prio is not 10"
89	cmd_jq "ip -n ${s_ns} -d -j link show eth2" \
90		".[].linkinfo.info_slave_data | select (.prio == 11)" "-e" &> /dev/null
91	check_err $? "eth2 prio is not 11"
92
93	bond_check_connection "setup"
94
95	# active slave should be the primary slave
96	check_active_slave eth1
97
98	# active slave should be the higher prio slave
99	ip -n ${s_ns} link set $active_slave down
100	check_active_slave eth2
101	bond_check_connection "fail over"
102
103	# when only 1 slave is up
104	ip -n ${s_ns} link set $active_slave down
105	check_active_slave eth0
106	bond_check_connection "only 1 slave up"
107
108	# when a higher prio slave change to up
109	ip -n ${s_ns} link set eth2 up
110	bond_check_connection "higher prio slave up"
111	case $primary_reselect in
112		"0")
113			check_active_slave "eth2"
114			;;
115		"1")
116			check_active_slave "eth0"
117			;;
118		"2")
119			check_active_slave "eth0"
120			;;
121	esac
122	local pre_active_slave=$active_slave
123
124	# when the primary slave change to up
125	ip -n ${s_ns} link set eth1 up
126	bond_check_connection "primary slave up"
127	case $primary_reselect in
128		"0")
129			check_active_slave "eth1"
130			;;
131		"1")
132			check_active_slave "$pre_active_slave"
133			;;
134		"2")
135			check_active_slave "$pre_active_slave"
136			ip -n ${s_ns} link set $active_slave down
137			bond_check_connection "pre_active slave down"
138			check_active_slave "eth1"
139			;;
140	esac
141
142	# Test changing bond slave prio
143	if [[ "$primary_reselect" == "0" ]];then
144		ip -n ${s_ns} link set eth0 type bond_slave prio 1000000
145		ip -n ${s_ns} link set eth1 type bond_slave prio 0
146		ip -n ${s_ns} link set eth2 type bond_slave prio -50
147		ip -n ${s_ns} -d link show eth0 | grep -q 'prio 1000000'
148		check_err $? "eth0 prio is not 1000000"
149		ip -n ${s_ns} -d link show eth1 | grep -q 'prio 0'
150		check_err $? "eth1 prio is not 0"
151		ip -n ${s_ns} -d link show eth2 | grep -q 'prio -50'
152		check_err $? "eth3 prio is not -50"
153		check_active_slave "eth1"
154
155		ip -n ${s_ns} link set $active_slave down
156		check_active_slave "eth0"
157		bond_check_connection "change slave prio"
158	fi
159}
160
161prio_miimon()
162{
163	local primary_reselect
164	local mode=$1
165
166	for primary_reselect in 0 1 2; do
167		prio_test "mode $mode miimon 100 primary eth1 primary_reselect $primary_reselect"
168		log_test "prio" "$mode miimon primary_reselect $primary_reselect"
169	done
170}
171
172prio_arp()
173{
174	local primary_reselect
175	local mode=$1
176
177	for primary_reselect in 0 1 2; do
178		prio_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} primary eth1 primary_reselect $primary_reselect"
179		log_test "prio" "$mode arp_ip_target primary_reselect $primary_reselect"
180	done
181}
182
183prio_ns()
184{
185	local primary_reselect
186	local mode=$1
187
188	if skip_ns; then
189		log_test_skip "prio ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
190		return 0
191	fi
192
193	for primary_reselect in 0 1 2; do
194		prio_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} primary eth1 primary_reselect $primary_reselect"
195		log_test "prio" "$mode ns_ip6_target primary_reselect $primary_reselect"
196	done
197}
198
199prio()
200{
201	local mode modes="active-backup balance-tlb balance-alb"
202
203	if skip_prio; then
204		log_test_skip "prio" "Current iproute or kernel doesn't support bond option 'prio'."
205		return 0
206	fi
207
208	for mode in $modes; do
209		prio_miimon $mode
210	done
211	prio_arp "active-backup"
212	prio_ns "active-backup"
213}
214
215wait_mii_up()
216{
217	for i in $(seq 0 2); do
218		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
219		[ ${mii_status} != "UP" ] && return 1
220	done
221	return 0
222}
223
224arp_validate_test()
225{
226	local param="$1"
227	RET=0
228
229	# create bond
230	bond_reset "${param}"
231
232	bond_check_connection
233	[ $RET -ne 0 ] && log_test "arp_validate" "$retmsg"
234
235	# wait for a while to make sure the mii status stable
236	slowwait 5 wait_mii_up
237	for i in $(seq 0 2); do
238		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
239		if [ ${mii_status} != "UP" ]; then
240			RET=1
241			log_test "arp_validate" "interface eth$i mii_status $mii_status"
242		fi
243	done
244}
245
246# Testing correct multicast groups are added to slaves for ns targets
247arp_validate_mcast()
248{
249	RET=0
250	local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
251	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
252
253	for i in $(seq 0 2); do
254		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
255
256		# arp_valid == 0 or active_slave should not join any maddrs
257		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
258			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
259			RET=1
260			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
261		# arp_valid != 0 and backup_slave should join both maddrs
262		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
263		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
264		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
265			RET=1
266			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
267		fi
268	done
269
270	# Do failover
271	ip -n ${s_ns} link set ${active_slave} down
272	# wait for active link change
273	slowwait 2 active_slave_changed $active_slave
274	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
275
276	for i in $(seq 0 2); do
277		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})
278
279		# arp_valid == 0 or active_slave should not join any maddrs
280		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
281			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
282			RET=1
283			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
284		# arp_valid != 0 and backup_slave should join both maddrs
285		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
286		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
287		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
288			RET=1
289			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
290		fi
291	done
292}
293
294arp_validate_arp()
295{
296	local mode=$1
297	local val
298	for val in $(seq 0 6); do
299		arp_validate_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} arp_validate $val"
300		log_test "arp_validate" "$mode arp_ip_target arp_validate $val"
301	done
302}
303
304arp_validate_ns()
305{
306	local mode=$1
307	local val
308
309	if skip_ns; then
310		log_test_skip "arp_validate ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
311		return 0
312	fi
313
314	for val in $(seq 0 6); do
315		arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
316		log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
317		arp_validate_mcast
318		log_test "arp_validate" "join mcast group"
319	done
320}
321
322arp_validate()
323{
324	arp_validate_arp "active-backup"
325	arp_validate_ns "active-backup"
326}
327
328garp_test()
329{
330	local param="$1"
331	local active_slave exp_num real_num i
332	RET=0
333
334	# create bond
335	bond_reset "${param}"
336
337	bond_check_connection
338	[ $RET -ne 0 ] && log_test "num_grat_arp" "$retmsg"
339
340
341	# Add tc rules to count GARP number
342	for i in $(seq 0 2); do
343		tc -n ${g_ns} filter add dev s$i ingress protocol arp pref 1 handle 101 \
344			flower skip_hw arp_op request arp_sip ${s_ip4} arp_tip ${s_ip4} action pass
345	done
346
347	# Do failover
348	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
349	ip -n ${s_ns} link set ${active_slave} down
350
351	# wait for active link change
352	slowwait 2 active_slave_changed $active_slave
353
354	exp_num=$(echo "${param}" | cut -f6 -d ' ')
355	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
356	slowwait_for_counter $((exp_num + 5)) $exp_num tc_rule_handle_stats_get \
357		"dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}" &> /dev/null
358
359	# check result
360	real_num=$(tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}")
361	if [ "${real_num}" -ne "${exp_num}" ]; then
362		echo "$real_num garp packets sent on active slave ${active_slave}"
363		RET=1
364	fi
365
366	for i in $(seq 0 2); do
367		tc -n ${g_ns} filter del dev s$i ingress
368	done
369}
370
371num_grat_arp()
372{
373	local val
374	for val in 10 20 30; do
375		garp_test "mode active-backup miimon 10 num_grat_arp $val peer_notify_delay 100"
376		log_test "num_grat_arp" "active-backup miimon num_grat_arp $val"
377	done
378}
379
380check_all_mac_same()
381{
382	RET=0
383	# all slaves should have same mac address (with the first port's mac)
384	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
385	local eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
386	local eth1_mac=$(ip -n "$s_ns" -j link show eth1 | jq -r '.[]["address"]')
387	local eth2_mac=$(ip -n "$s_ns" -j link show eth2 | jq -r '.[]["address"]')
388	if [ "$bond_mac" != "${mac[0]}" ] || [ "$eth0_mac" != "$bond_mac" ] || \
389		[ "$eth1_mac" != "$bond_mac" ] || [ "$eth2_mac" != "$bond_mac" ]; then
390		RET=1
391	fi
392}
393
394check_bond_mac_same_with_first()
395{
396	RET=0
397	# bond mac address should be same with the first added slave
398	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
399	if [ "$bond_mac" != "${mac[0]}" ]; then
400		RET=1
401	fi
402}
403
404check_bond_mac_same_with_active()
405{
406	RET=0
407	# bond mac address should be same with active slave
408	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
409	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
410	local active_slave_mac=$(ip -n "$s_ns" -j link show "$active_slave" | jq -r '.[]["address"]')
411	if [ "$bond_mac" != "$active_slave_mac" ]; then
412		RET=1
413	fi
414}
415
416check_backup_slave_mac_not_change()
417{
418	RET=0
419	# backup slave's mac address is not changed
420	if ip -n "$s_ns" -d -j link show type bond_slave | jq -e '.[]
421		| select(.linkinfo.info_slave_data.state=="BACKUP")
422		| select(.address != .linkinfo.info_slave_data.perm_hwaddr)' &> /dev/null; then
423		RET=1
424	fi
425}
426
427check_backup_slave_mac_inherit()
428{
429	local backup_mac
430	RET=0
431
432	# backup slaves should use mac[1] or mac[2]
433	local backup_macs=$(ip -n "$s_ns" -d -j link show type bond_slave | \
434		jq -r '.[] | select(.linkinfo.info_slave_data.state=="BACKUP") | .address')
435	for backup_mac in $backup_macs; do
436		if [ "$backup_mac" != "${mac[1]}" ] && [ "$backup_mac" != "${mac[2]}" ]; then
437			RET=1
438		fi
439	done
440}
441
442check_first_slave_random_mac()
443{
444	RET=0
445	# remove the first added slave and added it back
446	ip -n "$s_ns" link set eth0 nomaster
447	ip -n "$s_ns" link set eth0 master bond0
448
449	# the first slave should use random mac address
450	eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
451	[ "$eth0_mac" = "${mac[0]}" ] && RET=1
452	log_test "bond fail_over_mac follow" "random first slave mac"
453
454	# remove the first slave, the permanent MAC address should be restored back
455	ip -n "$s_ns" link set eth0 nomaster
456	eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
457	[ "$eth0_mac" != "${mac[0]}" ] && RET=1
458}
459
460do_active_backup_failover()
461{
462	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
463	ip -n ${s_ns} link set ${active_slave} down
464	slowwait 2 active_slave_changed $active_slave
465	ip -n ${s_ns} link set ${active_slave} up
466}
467
468fail_over_mac()
469{
470	# Bring down the first interface on the switch to force the bond to
471	# select another active interface instead of the first one that joined.
472	ip -n "$g_ns" link set s0 down
473
474	# fail_over_mac none
475	bond_reset "mode active-backup miimon 100 fail_over_mac 0"
476	check_all_mac_same
477	log_test "fail_over_mac 0" "all slaves have same mac"
478	do_active_backup_failover
479	check_all_mac_same
480	log_test "fail_over_mac 0" "failover: all slaves have same mac"
481
482	# fail_over_mac active
483	bond_reset "mode active-backup miimon 100 fail_over_mac 1"
484	check_bond_mac_same_with_active
485	log_test "fail_over_mac 1" "bond mac is same with active slave mac"
486	check_backup_slave_mac_not_change
487	log_test "fail_over_mac 1" "backup slave mac is not changed"
488	do_active_backup_failover
489	check_bond_mac_same_with_active
490	log_test "fail_over_mac 1" "failover: bond mac is same with active slave mac"
491	check_backup_slave_mac_not_change
492	log_test "fail_over_mac 1" "failover: backup slave mac is not changed"
493
494	# fail_over_mac follow
495	bond_reset "mode active-backup miimon 100 fail_over_mac 2"
496	check_bond_mac_same_with_first
497	log_test "fail_over_mac 2" "bond mac is same with first slave mac"
498	check_bond_mac_same_with_active
499	log_test "fail_over_mac 2" "bond mac is same with active slave mac"
500	check_backup_slave_mac_inherit
501	log_test "fail_over_mac 2" "backup slave mac inherit"
502	do_active_backup_failover
503	check_bond_mac_same_with_first
504	log_test "fail_over_mac 2" "failover: bond mac is same with first slave mac"
505	check_bond_mac_same_with_active
506	log_test "fail_over_mac 2" "failover: bond mac is same with active slave mac"
507	check_backup_slave_mac_inherit
508	log_test "fail_over_mac 2" "failover: backup slave mac inherit"
509	check_first_slave_random_mac
510	log_test "fail_over_mac 2" "first slave mac random"
511
512}
513
514trap cleanup EXIT
515
516setup_prepare
517setup_wait
518tests_run
519
520exit $EXIT_STATUS
521