aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/drivers/net/bonding/bond_options.sh
blob: 187b478d0ddf2932c8169a0df6d549765e766470 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test bonding options with mode 1,5,6

ALL_TESTS="
	prio
	arp_validate
	num_grat_arp
	fail_over_mac
	vlan_over_bond
"

lib_dir=$(dirname "$0")
source ${lib_dir}/bond_topo_3d1c.sh
c_maddr="33:33:ff:00:00:10"
g_maddr="33:33:ff:00:02:54"

skip_prio()
{
	local skip=1

	# check if iproute support prio option
	ip -n ${s_ns} link set eth0 type bond_slave prio 10
	[[ $? -ne 0 ]] && skip=0

	# check if kernel support prio option
	ip -n ${s_ns} -d link show eth0 | grep -q "prio 10"
	[[ $? -ne 0 ]] && skip=0

	return $skip
}

skip_ns()
{
	local skip=1

	# check if iproute support ns_ip6_target option
	ip -n ${s_ns} link add bond1 type bond ns_ip6_target ${g_ip6}
	[[ $? -ne 0 ]] && skip=0

	# check if kernel support ns_ip6_target option
	ip -n ${s_ns} -d link show bond1 | grep -q "ns_ip6_target ${g_ip6}"
	[[ $? -ne 0 ]] && skip=0

	ip -n ${s_ns} link del bond1

	return $skip
}

active_slave=""
active_slave_changed()
{
	local old_active_slave=$1
	local new_active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" \
				".[].linkinfo.info_data.active_slave")
	[ "$new_active_slave" != "$old_active_slave" -a "$new_active_slave" != "null" ]
}

check_active_slave()
{
	local target_active_slave=$1
	slowwait 5 active_slave_changed $active_slave
	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
	test "$active_slave" = "$target_active_slave"
	check_err $? "Current active slave is $active_slave but not $target_active_slave"
}

# Test bonding prio option
prio_test()
{
	local param="$1"
	RET=0

	# create bond
	bond_reset "${param}"
	# set active_slave to primary eth1 specifically
	ip -n ${s_ns} link set bond0 type bond active_slave eth1

	# check bonding member prio value
	ip -n ${s_ns} link set eth0 type bond_slave prio 0
	ip -n ${s_ns} link set eth1 type bond_slave prio 10
	ip -n ${s_ns} link set eth2 type bond_slave prio 11
	cmd_jq "ip -n ${s_ns} -d -j link show eth0" \
		".[].linkinfo.info_slave_data | select (.prio == 0)" "-e" &> /dev/null
	check_err $? "eth0 prio is not 0"
	cmd_jq "ip -n ${s_ns} -d -j link show eth1" \
		".[].linkinfo.info_slave_data | select (.prio == 10)" "-e" &> /dev/null
	check_err $? "eth1 prio is not 10"
	cmd_jq "ip -n ${s_ns} -d -j link show eth2" \
		".[].linkinfo.info_slave_data | select (.prio == 11)" "-e" &> /dev/null
	check_err $? "eth2 prio is not 11"

	bond_check_connection "setup"

	# active slave should be the primary slave
	check_active_slave eth1

	# active slave should be the higher prio slave
	ip -n ${s_ns} link set $active_slave down
	check_active_slave eth2
	bond_check_connection "fail over"

	# when only 1 slave is up
	ip -n ${s_ns} link set $active_slave down
	check_active_slave eth0
	bond_check_connection "only 1 slave up"

	# when a higher prio slave change to up
	ip -n ${s_ns} link set eth2 up
	bond_check_connection "higher prio slave up"
	case $primary_reselect in
		"0")
			check_active_slave "eth2"
			;;
		"1")
			check_active_slave "eth0"
			;;
		"2")
			check_active_slave "eth0"
			;;
	esac
	local pre_active_slave=$active_slave

	# when the primary slave change to up
	ip -n ${s_ns} link set eth1 up
	bond_check_connection "primary slave up"
	case $primary_reselect in
		"0")
			check_active_slave "eth1"
			;;
		"1")
			check_active_slave "$pre_active_slave"
			;;
		"2")
			check_active_slave "$pre_active_slave"
			ip -n ${s_ns} link set $active_slave down
			bond_check_connection "pre_active slave down"
			check_active_slave "eth1"
			;;
	esac

	# Test changing bond slave prio
	if [[ "$primary_reselect" == "0" ]];then
		ip -n ${s_ns} link set eth0 type bond_slave prio 1000000
		ip -n ${s_ns} link set eth1 type bond_slave prio 0
		ip -n ${s_ns} link set eth2 type bond_slave prio -50
		ip -n ${s_ns} -d link show eth0 | grep -q 'prio 1000000'
		check_err $? "eth0 prio is not 1000000"
		ip -n ${s_ns} -d link show eth1 | grep -q 'prio 0'
		check_err $? "eth1 prio is not 0"
		ip -n ${s_ns} -d link show eth2 | grep -q 'prio -50'
		check_err $? "eth3 prio is not -50"
		check_active_slave "eth1"

		ip -n ${s_ns} link set $active_slave down
		check_active_slave "eth0"
		bond_check_connection "change slave prio"
	fi
}

prio_miimon()
{
	local primary_reselect
	local mode=$1

	for primary_reselect in 0 1 2; do
		prio_test "mode $mode miimon 100 primary eth1 primary_reselect $primary_reselect"
		log_test "prio" "$mode miimon primary_reselect $primary_reselect"
	done
}

prio_arp()
{
	local primary_reselect
	local mode=$1

	for primary_reselect in 0 1 2; do
		prio_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} primary eth1 primary_reselect $primary_reselect"
		log_test "prio" "$mode arp_ip_target primary_reselect $primary_reselect"
	done
}

prio_ns()
{
	local primary_reselect
	local mode=$1

	if skip_ns; then
		log_test_skip "prio ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
		return 0
	fi

	for primary_reselect in 0 1 2; do
		prio_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6} primary eth1 primary_reselect $primary_reselect"
		log_test "prio" "$mode ns_ip6_target primary_reselect $primary_reselect"
	done
}

prio()
{
	local mode modes="active-backup balance-tlb balance-alb"

	if skip_prio; then
		log_test_skip "prio" "Current iproute or kernel doesn't support bond option 'prio'."
		return 0
	fi

	for mode in $modes; do
		prio_miimon $mode
	done
	prio_arp "active-backup"
	prio_ns "active-backup"
}

wait_mii_up()
{
	for i in $(seq 0 2); do
		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
		[ ${mii_status} != "UP" ] && return 1
	done
	return 0
}

arp_validate_test()
{
	local param="$1"
	RET=0

	# create bond
	bond_reset "${param}"

	bond_check_connection
	[ $RET -ne 0 ] && log_test "arp_validate" "$retmsg"

	# wait for a while to make sure the mii status stable
	slowwait 5 wait_mii_up
	for i in $(seq 0 2); do
		mii_status=$(cmd_jq "ip -n ${s_ns} -j -d link show eth$i" ".[].linkinfo.info_slave_data.mii_status")
		if [ ${mii_status} != "UP" ]; then
			RET=1
			log_test "arp_validate" "interface eth$i mii_status $mii_status"
		fi
	done
}

# Testing correct multicast groups are added to slaves for ns targets
arp_validate_mcast()
{
	RET=0
	local arp_valid=$(cmd_jq "ip -n ${s_ns} -j -d link show bond0" ".[].linkinfo.info_data.arp_validate")
	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")

	for i in $(seq 0 2); do
		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})

		# arp_valid == 0 or active_slave should not join any maddrs
		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
			RET=1
			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
		# arp_valid != 0 and backup_slave should join both maddrs
		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
			RET=1
			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
		fi
	done

	# Do failover
	ip -n ${s_ns} link set ${active_slave} down
	# wait for active link change
	slowwait 2 active_slave_changed $active_slave
	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")

	for i in $(seq 0 2); do
		maddr_list=$(ip -n ${s_ns} maddr show dev eth${i})

		# arp_valid == 0 or active_slave should not join any maddrs
		if { [ "$arp_valid" == "null" ] || [ "eth${i}" == ${active_slave} ]; } && \
			echo "$maddr_list" | grep -qE "${c_maddr}|${g_maddr}"; then
			RET=1
			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
		# arp_valid != 0 and backup_slave should join both maddrs
		elif [ "$arp_valid" != "null" ] && [ "eth${i}" != ${active_slave} ] && \
		     ( ! echo "$maddr_list" | grep -q "${c_maddr}" || \
		       ! echo "$maddr_list" | grep -q "${m_maddr}"); then
			RET=1
			check_err 1 "arp_valid $arp_valid active_slave $active_slave, eth$i has mcast group"
		fi
	done
}

arp_validate_arp()
{
	local mode=$1
	local val
	for val in $(seq 0 6); do
		arp_validate_test "mode $mode arp_interval 100 arp_ip_target ${g_ip4} arp_validate $val"
		log_test "arp_validate" "$mode arp_ip_target arp_validate $val"
	done
}

arp_validate_ns()
{
	local mode=$1
	local val

	if skip_ns; then
		log_test_skip "arp_validate ns" "Current iproute or kernel doesn't support bond option 'ns_ip6_target'."
		return 0
	fi

	for val in $(seq 0 6); do
		arp_validate_test "mode $mode arp_interval 100 ns_ip6_target ${g_ip6},${c_ip6} arp_validate $val"
		log_test "arp_validate" "$mode ns_ip6_target arp_validate $val"
		arp_validate_mcast
		log_test "arp_validate" "join mcast group"
	done
}

arp_validate()
{
	arp_validate_arp "active-backup"
	arp_validate_ns "active-backup"
}

garp_test()
{
	local param="$1"
	local active_slave exp_num real_num i
	RET=0

	# create bond
	bond_reset "${param}"

	bond_check_connection
	[ $RET -ne 0 ] && log_test "num_grat_arp" "$retmsg"


	# Add tc rules to count GARP number
	for i in $(seq 0 2); do
		tc -n ${g_ns} filter add dev s$i ingress protocol arp pref 1 handle 101 \
			flower skip_hw arp_op request arp_sip ${s_ip4} arp_tip ${s_ip4} action pass
	done

	# Do failover
	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
	ip -n ${s_ns} link set ${active_slave} down

	# wait for active link change
	slowwait 2 active_slave_changed $active_slave

	exp_num=$(echo "${param}" | cut -f6 -d ' ')
	active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
	slowwait_for_counter $((exp_num + 5)) $exp_num tc_rule_handle_stats_get \
		"dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}" &> /dev/null

	# check result
	real_num=$(tc_rule_handle_stats_get "dev s${active_slave#eth} ingress" 101 ".packets" "-n ${g_ns}")
	if [ "${real_num}" -ne "${exp_num}" ]; then
		echo "$real_num garp packets sent on active slave ${active_slave}"
		RET=1
	fi

	for i in $(seq 0 2); do
		tc -n ${g_ns} filter del dev s$i ingress
	done
}

num_grat_arp()
{
	local val
	for val in 10 20 30; do
		garp_test "mode active-backup miimon 10 num_grat_arp $val peer_notify_delay 100"
		log_test "num_grat_arp" "active-backup miimon num_grat_arp $val"
	done
}

check_all_mac_same()
{
	RET=0
	# all slaves should have same mac address (with the first port's mac)
	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
	local eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
	local eth1_mac=$(ip -n "$s_ns" -j link show eth1 | jq -r '.[]["address"]')
	local eth2_mac=$(ip -n "$s_ns" -j link show eth2 | jq -r '.[]["address"]')
	if [ "$bond_mac" != "${mac[0]}" ] || [ "$eth0_mac" != "$bond_mac" ] || \
		[ "$eth1_mac" != "$bond_mac" ] || [ "$eth2_mac" != "$bond_mac" ]; then
		RET=1
	fi
}

check_bond_mac_same_with_first()
{
	RET=0
	# bond mac address should be same with the first added slave
	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
	if [ "$bond_mac" != "${mac[0]}" ]; then
		RET=1
	fi
}

check_bond_mac_same_with_active()
{
	RET=0
	# bond mac address should be same with active slave
	local bond_mac=$(ip -n "$s_ns" -j link show bond0 | jq -r '.[]["address"]')
	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
	local active_slave_mac=$(ip -n "$s_ns" -j link show "$active_slave" | jq -r '.[]["address"]')
	if [ "$bond_mac" != "$active_slave_mac" ]; then
		RET=1
	fi
}

check_backup_slave_mac_not_change()
{
	RET=0
	# backup slave's mac address is not changed
	if ip -n "$s_ns" -d -j link show type bond_slave | jq -e '.[]
		| select(.linkinfo.info_slave_data.state=="BACKUP")
		| select(.address != .linkinfo.info_slave_data.perm_hwaddr)' &> /dev/null; then
		RET=1
	fi
}

check_backup_slave_mac_inherit()
{
	local backup_mac
	RET=0

	# backup slaves should use mac[1] or mac[2]
	local backup_macs=$(ip -n "$s_ns" -d -j link show type bond_slave | \
		jq -r '.[] | select(.linkinfo.info_slave_data.state=="BACKUP") | .address')
	for backup_mac in $backup_macs; do
		if [ "$backup_mac" != "${mac[1]}" ] && [ "$backup_mac" != "${mac[2]}" ]; then
			RET=1
		fi
	done
}

check_first_slave_random_mac()
{
	RET=0
	# remove the first added slave and added it back
	ip -n "$s_ns" link set eth0 nomaster
	ip -n "$s_ns" link set eth0 master bond0

	# the first slave should use random mac address
	eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
	[ "$eth0_mac" = "${mac[0]}" ] && RET=1
	log_test "bond fail_over_mac follow" "random first slave mac"

	# remove the first slave, the permanent MAC address should be restored back
	ip -n "$s_ns" link set eth0 nomaster
	eth0_mac=$(ip -n "$s_ns" -j link show eth0 | jq -r '.[]["address"]')
	[ "$eth0_mac" != "${mac[0]}" ] && RET=1
}

do_active_backup_failover()
{
	local active_slave=$(cmd_jq "ip -n ${s_ns} -d -j link show bond0" ".[].linkinfo.info_data.active_slave")
	ip -n ${s_ns} link set ${active_slave} down
	slowwait 2 active_slave_changed $active_slave
	ip -n ${s_ns} link set ${active_slave} up
}

fail_over_mac()
{
	# Bring down the first interface on the switch to force the bond to
	# select another active interface instead of the first one that joined.
	ip -n "$g_ns" link set s0 down

	# fail_over_mac none
	bond_reset "mode active-backup miimon 100 fail_over_mac 0"
	check_all_mac_same
	log_test "fail_over_mac 0" "all slaves have same mac"
	do_active_backup_failover
	check_all_mac_same
	log_test "fail_over_mac 0" "failover: all slaves have same mac"

	# fail_over_mac active
	bond_reset "mode active-backup miimon 100 fail_over_mac 1"
	check_bond_mac_same_with_active
	log_test "fail_over_mac 1" "bond mac is same with active slave mac"
	check_backup_slave_mac_not_change
	log_test "fail_over_mac 1" "backup slave mac is not changed"
	do_active_backup_failover
	check_bond_mac_same_with_active
	log_test "fail_over_mac 1" "failover: bond mac is same with active slave mac"
	check_backup_slave_mac_not_change
	log_test "fail_over_mac 1" "failover: backup slave mac is not changed"

	# fail_over_mac follow
	bond_reset "mode active-backup miimon 100 fail_over_mac 2"
	check_bond_mac_same_with_first
	log_test "fail_over_mac 2" "bond mac is same with first slave mac"
	check_bond_mac_same_with_active
	log_test "fail_over_mac 2" "bond mac is same with active slave mac"
	check_backup_slave_mac_inherit
	log_test "fail_over_mac 2" "backup slave mac inherit"
	do_active_backup_failover
	check_bond_mac_same_with_first
	log_test "fail_over_mac 2" "failover: bond mac is same with first slave mac"
	check_bond_mac_same_with_active
	log_test "fail_over_mac 2" "failover: bond mac is same with active slave mac"
	check_backup_slave_mac_inherit
	log_test "fail_over_mac 2" "failover: backup slave mac inherit"
	check_first_slave_random_mac
	log_test "fail_over_mac 2" "first slave mac random"
}

vlan_over_bond_arp()
{
	local mode="$1"
	RET=0

	bond_reset "mode $mode arp_interval 100 arp_ip_target 192.0.3.10"
	ip -n "${s_ns}" link add bond0.3 link bond0 type vlan id 3
	ip -n "${s_ns}" link set bond0.3 up
	ip -n "${s_ns}" addr add 192.0.3.1/24 dev bond0.3
	ip -n "${s_ns}" addr add 2001:db8::3:1/64 dev bond0.3

	slowwait_for_counter 5 5 tc_rule_handle_stats_get \
		"dev eth0.3 ingress" 101 ".packets" "-n ${c_ns}" &> /dev/null || RET=1
	log_test "vlan over bond arp" "$mode"
}

vlan_over_bond_ns()
{
	local mode="$1"
	RET=0

	if skip_ns; then
		log_test_skip "vlan_over_bond ns" "$mode"
		return 0
	fi

	bond_reset "mode $mode arp_interval 100 ns_ip6_target 2001:db8::3:10"
	ip -n "${s_ns}" link add bond0.3 link bond0 type vlan id 3
	ip -n "${s_ns}" link set bond0.3 up
	ip -n "${s_ns}" addr add 192.0.3.1/24 dev bond0.3
	ip -n "${s_ns}" addr add 2001:db8::3:1/64 dev bond0.3

	slowwait_for_counter 5 5 tc_rule_handle_stats_get \
		"dev eth0.3 ingress" 102 ".packets" "-n ${c_ns}" &> /dev/null || RET=1
	log_test "vlan over bond ns" "$mode"
}

vlan_over_bond()
{
	# add vlan 3 for client
	ip -n "${c_ns}" link add eth0.3 link eth0 type vlan id 3
	ip -n "${c_ns}" link set eth0.3 up
	ip -n "${c_ns}" addr add 192.0.3.10/24 dev eth0.3
	ip -n "${c_ns}" addr add 2001:db8::3:10/64 dev eth0.3

	# Add tc rule to check the vlan pkts
	tc -n "${c_ns}" qdisc add dev eth0.3 clsact
	tc -n "${c_ns}" filter add dev eth0.3 ingress protocol arp \
		handle 101 flower skip_hw arp_op request \
		arp_sip 192.0.3.1 arp_tip 192.0.3.10 action pass
	tc -n "${c_ns}" filter add dev eth0.3 ingress protocol ipv6 \
		handle 102 flower skip_hw ip_proto icmpv6 \
		type 135 src_ip 2001:db8::3:1 action pass

	vlan_over_bond_arp "active-backup"
	vlan_over_bond_ns "active-backup"
}

trap cleanup EXIT

setup_prepare
setup_wait
tests_run

exit $EXIT_STATUS