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