| #!/bin/bash | |
| # SPDX-License-Identifier: GPL-2.0 | |
| # These tests verify the decoupled RX and TX enablement of team driver member | |
| # interfaces. | |
| # | |
| # Topology | |
| # | |
| # +---------------------+ NS1 | |
| # | test_team1 | | |
| # | | | | |
| # | eth0 | | |
| # | | | | |
| # | | | | |
| # +---------------------+ | |
| # | | |
| # +---------------------+ NS2 | |
| # | | | | |
| # | | | | |
| # | eth0 | | |
| # | | | | |
| # | test_team2 | | |
| # +---------------------+ | |
| export ALL_TESTS=" | |
| team_test_tx_enablement | |
| team_test_rx_enablement | |
| " | |
| test_dir="$(dirname "$0")" | |
| # shellcheck disable=SC1091 | |
| source "${test_dir}/../../../net/lib.sh" | |
| # shellcheck disable=SC1091 | |
| source "${test_dir}/team_lib.sh" | |
| NS1="" | |
| NS2="" | |
| export NODAD="nodad" | |
| PREFIX_LENGTH="64" | |
| NS1_IP="fd00::1" | |
| NS2_IP="fd00::2" | |
| NS1_IP4="192.168.0.1" | |
| NS2_IP4="192.168.0.2" | |
| MEMBERS=("eth0") | |
| PING_COUNT=5 | |
| PING_TIMEOUT_S=1 | |
| PING_INTERVAL=0.1 | |
| while getopts "4" opt; do | |
| case $opt in | |
| 4) | |
| echo "IPv4 mode selected." | |
| export NODAD= | |
| PREFIX_LENGTH="24" | |
| NS1_IP="${NS1_IP4}" | |
| NS2_IP="${NS2_IP4}" | |
| ;; | |
| \?) | |
| echo "Invalid option: -$OPTARG" >&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| # This has to be sourced after opts are gathered... | |
| export REQUIRE_MZ=no | |
| export NUM_NETIFS=0 | |
| # shellcheck disable=SC1091 | |
| source "${test_dir}/../../../net/forwarding/lib.sh" | |
| # Create the network namespaces, veth pair, and team devices in the specified | |
| # mode. | |
| # Globals: | |
| # RET - Used by test infra, set by `check_err` functions. | |
| # Arguments: | |
| # mode - The team driver mode to use for the team devices. | |
| environment_create() | |
| { | |
| trap cleanup_all_ns EXIT | |
| setup_ns ns1 ns2 | |
| NS1="${NS_LIST[0]}" | |
| NS2="${NS_LIST[1]}" | |
| # Create the interfaces. | |
| ip -n "${NS1}" link add eth0 type veth peer name eth0 netns "${NS2}" | |
| ip -n "${NS1}" link add test_team1 type team | |
| ip -n "${NS2}" link add test_team2 type team | |
| # Set up the receiving network namespace's team interface. | |
| setup_team "${NS2}" test_team2 roundrobin "${NS2_IP}" \ | |
| "${PREFIX_LENGTH}" "${MEMBERS[@]}" | |
| } | |
| # Set a particular option value for team or team port. | |
| # Arguments: | |
| # namespace - The namespace name that has the team. | |
| # option_name - The option name to set. | |
| # option_value - The value to set the option to. | |
| # team_name - The name of team to set the option for. | |
| # member_name - The (optional) optional name of the member port. | |
| set_option_value() | |
| { | |
| local namespace="$1" | |
| local option_name="$2" | |
| local option_value="$3" | |
| local team_name="$4" | |
| local member_name="$5" | |
| local port_flag="--port=${member_name}" | |
| ip netns exec "${namespace}" teamnl "${team_name}" setoption \ | |
| "${option_name}" "${option_value}" "${port_flag}" | |
| return $? | |
| } | |
| # Send some pings and return the ping command return value. | |
| try_ping() | |
| { | |
| ip netns exec "${NS1}" ping -i "${PING_INTERVAL}" -c "${PING_COUNT}" \ | |
| "${NS2_IP}" -W "${PING_TIMEOUT_S}" | |
| } | |
| # Checks tcpdump output from net/forwarding lib, and checks if there are any | |
| # ICMP(4 or 6) packets. | |
| # Arguments: | |
| # interface - The interface name to search for. | |
| # ip_address - The destination IP address (4 or 6) to search for. | |
| did_interface_receive_icmp() | |
| { | |
| local interface="$1" | |
| local ip_address="$2" | |
| local packet_count | |
| packet_count=$(tcpdump_show "$interface" | grep -c \ | |
| "> ${ip_address}: ICMP") | |
| echo "Packet count for ${interface} was ${packet_count}" | |
| if [[ "$packet_count" -gt 0 ]]; then | |
| true | |
| else | |
| false | |
| fi | |
| } | |
| # Test JUST tx enablement with a given mode. | |
| # Globals: | |
| # RET - Used by test infra, set by `check_err` functions. | |
| # Arguments: | |
| # mode - The mode to set the team interfaces to. | |
| team_test_mode_tx_enablement() | |
| { | |
| local mode="$1" | |
| export RET=0 | |
| # Set up the sender team with the correct mode. | |
| setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \ | |
| "${PREFIX_LENGTH}" "${MEMBERS[@]}" | |
| check_err $? "Failed to set up sender team" | |
| ### Scenario 1: Member interface initially enabled. | |
| # Expect ping to pass | |
| try_ping | |
| check_err $? "Ping failed when TX enabled" | |
| ### Scenario 2: One tx-side interface disabled. | |
| # Expect ping to fail. | |
| set_option_value "${NS1}" tx_enabled false test_team1 eth0 | |
| check_err $? "Failed to disable TX" | |
| tcpdump_start eth0 "${NS2}" | |
| try_ping | |
| check_fail $? "Ping succeeded when TX disabled" | |
| tcpdump_stop eth0 | |
| # Expect no packets to be transmitted, since TX is disabled. | |
| did_interface_receive_icmp eth0 "${NS2_IP}" | |
| check_fail $? "eth0 IS transmitting when TX disabled" | |
| tcpdump_cleanup eth0 | |
| ### Scenario 3: The interface has tx re-enabled. | |
| # Expect ping to pass. | |
| set_option_value "${NS1}" tx_enabled true test_team1 eth0 | |
| check_err $? "Failed to reenable TX" | |
| try_ping | |
| check_err $? "Ping failed when TX reenabled" | |
| log_test "TX failover of '${mode}' test" | |
| } | |
| # Test JUST rx enablement with a given mode. | |
| # Globals: | |
| # RET - Used by test infra, set by `check_err` functions. | |
| # Arguments: | |
| # mode - The mode to set the team interfaces to. | |
| team_test_mode_rx_enablement() | |
| { | |
| local mode="$1" | |
| export RET=0 | |
| # Set up the sender team with the correct mode. | |
| setup_team "${NS1}" test_team1 "${mode}" "${NS1_IP}" \ | |
| "${PREFIX_LENGTH}" "${MEMBERS[@]}" | |
| check_err $? "Failed to set up sender team" | |
| ### Scenario 1: Member interface initially enabled. | |
| # Expect ping to pass | |
| try_ping | |
| check_err $? "Ping failed when RX enabled" | |
| ### Scenario 2: One rx-side interface disabled. | |
| # Expect ping to fail. | |
| set_option_value "${NS1}" rx_enabled false test_team1 eth0 | |
| check_err $? "Failed to disable RX" | |
| tcpdump_start eth0 "${NS2}" | |
| try_ping | |
| check_fail $? "Ping succeeded when RX disabled" | |
| tcpdump_stop eth0 | |
| # Expect packets to be transmitted, since only RX is disabled. | |
| did_interface_receive_icmp eth0 "${NS2_IP}" | |
| check_err $? "eth0 not transmitting when RX disabled" | |
| tcpdump_cleanup eth0 | |
| ### Scenario 3: The interface has rx re-enabled. | |
| # Expect ping to pass. | |
| set_option_value "${NS1}" rx_enabled true test_team1 eth0 | |
| check_err $? "Failed to reenable RX" | |
| try_ping | |
| check_err $? "Ping failed when RX reenabled" | |
| log_test "RX failover of '${mode}' test" | |
| } | |
| team_test_tx_enablement() | |
| { | |
| team_test_mode_tx_enablement broadcast | |
| team_test_mode_tx_enablement roundrobin | |
| team_test_mode_tx_enablement random | |
| } | |
| team_test_rx_enablement() | |
| { | |
| team_test_mode_rx_enablement broadcast | |
| team_test_mode_rx_enablement roundrobin | |
| team_test_mode_rx_enablement random | |
| } | |
| require_command teamnl | |
| require_command tcpdump | |
| require_command ping | |
| environment_create | |
| tests_run | |
| exit "${EXIT_STATUS}" |