Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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