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