| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| # |
| # Test bonding options with mode 1,5,6 |
| |
| ALL_TESTS=" |
| prio |
| arp_validate |
| num_grat_arp |
| " |
| |
| lib_dir=$(dirname "$0") |
| source ${lib_dir}/bond_topo_3d1c.sh |
| c_maddr="33:33:00:00:00:10" |
| g_maddr="33:33:00: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}" |
| |
| # 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 |
| } |
| |
| trap cleanup EXIT |
| |
| setup_prepare |
| setup_wait |
| tests_run |
| |
| exit $EXIT_STATUS |