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