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