|
|
|
|
@ -0,0 +1,246 @@
|
|
|
|
|
#!/bin/bash
|
|
|
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
|
|
|
|
# These tests verify that teamd is able to enable and disable ports via the
|
|
|
|
|
# active backup runner.
|
|
|
|
|
#
|
|
|
|
|
# Topology:
|
|
|
|
|
#
|
|
|
|
|
# +-------------------------+ NS1
|
|
|
|
|
# | test_team1 |
|
|
|
|
|
# | + |
|
|
|
|
|
# | eth0 | eth1 |
|
|
|
|
|
# | +---+---+ |
|
|
|
|
|
# | | | |
|
|
|
|
|
# +-------------------------+
|
|
|
|
|
# | |
|
|
|
|
|
# +-------------------------+ NS2
|
|
|
|
|
# | | | |
|
|
|
|
|
# | +-------+ |
|
|
|
|
|
# | eth0 | eth1 |
|
|
|
|
|
# | + |
|
|
|
|
|
# | test_team2 |
|
|
|
|
|
# +-------------------------+
|
|
|
|
|
|
|
|
|
|
export ALL_TESTS="teamd_test_active_backup"
|
|
|
|
|
|
|
|
|
|
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"
|
|
|
|
|
NS1_TEAMD_CONF=""
|
|
|
|
|
NS2_TEAMD_CONF=""
|
|
|
|
|
NS1_TEAMD_PID=""
|
|
|
|
|
NS2_TEAMD_PID=""
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
teamd_config_create()
|
|
|
|
|
{
|
|
|
|
|
local runner=$1
|
|
|
|
|
local dev=$2
|
|
|
|
|
local conf
|
|
|
|
|
|
|
|
|
|
conf=$(mktemp)
|
|
|
|
|
|
|
|
|
|
cat > "${conf}" <<-EOF
|
|
|
|
|
{
|
|
|
|
|
"device": "${dev}",
|
|
|
|
|
"runner": {"name": "${runner}"},
|
|
|
|
|
"ports": {
|
|
|
|
|
"eth0": {},
|
|
|
|
|
"eth1": {}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EOF
|
|
|
|
|
echo "${conf}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Create the network namespaces, veth pair, and team devices in the specified
|
|
|
|
|
# runner.
|
|
|
|
|
# Globals:
|
|
|
|
|
# RET - Used by test infra, set by `check_err` functions.
|
|
|
|
|
# Arguments:
|
|
|
|
|
# runner - The Teamd runner to use for the Team devices.
|
|
|
|
|
environment_create()
|
|
|
|
|
{
|
|
|
|
|
local runner=$1
|
|
|
|
|
|
|
|
|
|
echo "Setting up two-link aggregation for runner ${runner}"
|
|
|
|
|
echo "Teamd version is: $(teamd --version)"
|
|
|
|
|
trap environment_destroy EXIT
|
|
|
|
|
|
|
|
|
|
setup_ns ns1 ns2
|
|
|
|
|
NS1="${NS_LIST[0]}"
|
|
|
|
|
NS2="${NS_LIST[1]}"
|
|
|
|
|
|
|
|
|
|
for link in $(seq 0 1); do
|
|
|
|
|
ip -n "${NS1}" link add "eth${link}" type veth peer name \
|
|
|
|
|
"eth${link}" netns "${NS2}"
|
|
|
|
|
check_err $? "Failed to create veth pair"
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
NS1_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team1")
|
|
|
|
|
NS2_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team2")
|
|
|
|
|
echo "Conf files are ${NS1_TEAMD_CONF} and ${NS2_TEAMD_CONF}"
|
|
|
|
|
|
|
|
|
|
ip netns exec "${NS1}" teamd -d -f "${NS1_TEAMD_CONF}"
|
|
|
|
|
check_err $? "Failed to create team device in ${NS1}"
|
|
|
|
|
NS1_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS1_TEAMD_CONF}")
|
|
|
|
|
|
|
|
|
|
ip netns exec "${NS2}" teamd -d -f "${NS2_TEAMD_CONF}"
|
|
|
|
|
check_err $? "Failed to create team device in ${NS2}"
|
|
|
|
|
NS2_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS2_TEAMD_CONF}")
|
|
|
|
|
|
|
|
|
|
echo "Created team devices"
|
|
|
|
|
echo "Teamd PIDs are ${NS1_TEAMD_PID} and ${NS2_TEAMD_PID}"
|
|
|
|
|
|
|
|
|
|
ip -n "${NS1}" link set test_team1 up
|
|
|
|
|
check_err $? "Failed to set test_team1 up in ${NS1}"
|
|
|
|
|
ip -n "${NS2}" link set test_team2 up
|
|
|
|
|
check_err $? "Failed to set test_team2 up in ${NS2}"
|
|
|
|
|
|
|
|
|
|
ip -n "${NS1}" addr add "${NS1_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \
|
|
|
|
|
test_team1
|
|
|
|
|
check_err $? "Failed to add address to team device in ${NS1}"
|
|
|
|
|
ip -n "${NS2}" addr add "${NS2_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \
|
|
|
|
|
test_team2
|
|
|
|
|
check_err $? "Failed to add address to team device in ${NS2}"
|
|
|
|
|
|
|
|
|
|
slowwait 2 timeout 0.5 ip netns exec "${NS1}" ping -W 1 -c 1 "${NS2_IP}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Tear down the environment: kill teamd and delete network namespaces.
|
|
|
|
|
environment_destroy()
|
|
|
|
|
{
|
|
|
|
|
echo "Tearing down two-link aggregation"
|
|
|
|
|
|
|
|
|
|
rm "${NS1_TEAMD_CONF}"
|
|
|
|
|
rm "${NS2_TEAMD_CONF}"
|
|
|
|
|
|
|
|
|
|
# First, try graceful teamd teardown.
|
|
|
|
|
ip netns exec "${NS1}" teamd -k -t test_team1
|
|
|
|
|
ip netns exec "${NS2}" teamd -k -t test_team2
|
|
|
|
|
|
|
|
|
|
# If teamd can't be killed gracefully, then sigkill.
|
|
|
|
|
if kill -0 "${NS1_TEAMD_PID}" 2>/dev/null; then
|
|
|
|
|
echo "Sending sigkill to teamd for test_team1"
|
|
|
|
|
kill -9 "${NS1_TEAMD_PID}"
|
|
|
|
|
rm -f /var/run/teamd/test_team1.{pid,sock}
|
|
|
|
|
fi
|
|
|
|
|
if kill -0 "${NS2_TEAMD_PID}" 2>/dev/null; then
|
|
|
|
|
echo "Sending sigkill to teamd for test_team2"
|
|
|
|
|
kill -9 "${NS2_TEAMD_PID}"
|
|
|
|
|
rm -f /var/run/teamd/test_team2.{pid,sock}
|
|
|
|
|
fi
|
|
|
|
|
cleanup_all_ns
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Change the active port for an active-backup mode team.
|
|
|
|
|
# Arguments:
|
|
|
|
|
# namespace - The network namespace that the team is in.
|
|
|
|
|
# team - The name of the team.
|
|
|
|
|
# active_port - The port to make active.
|
|
|
|
|
set_active_port()
|
|
|
|
|
{
|
|
|
|
|
local namespace=$1
|
|
|
|
|
local team=$2
|
|
|
|
|
local active_port=$3
|
|
|
|
|
|
|
|
|
|
ip netns exec "${namespace}" teamdctl "${team}" state item set \
|
|
|
|
|
runner.active_port "${active_port}"
|
|
|
|
|
slowwait 2 bash -c "ip netns exec ${namespace} teamdctl ${team} state \
|
|
|
|
|
item get runner.active_port | grep -q ${active_port}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Wait for an interface to stop receiving traffic. If it keeps receiving traffic
|
|
|
|
|
# for the duration of the timeout, then return an error.
|
|
|
|
|
# Arguments:
|
|
|
|
|
# - namespace - The network namespace that the interface is in.
|
|
|
|
|
# - interface - The name of the interface.
|
|
|
|
|
wait_to_stop_receiving()
|
|
|
|
|
{
|
|
|
|
|
local namespace=$1
|
|
|
|
|
local interface=$2
|
|
|
|
|
|
|
|
|
|
echo "Waiting for ${interface} in ${namespace} to stop receiving"
|
|
|
|
|
slowwait 10 check_no_traffic "${interface}" "${NS2_IP}" \
|
|
|
|
|
"${namespace}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Test that active backup runner can change active ports.
|
|
|
|
|
# Globals:
|
|
|
|
|
# RET - Used by test infra, set by `check_err` functions.
|
|
|
|
|
teamd_test_active_backup()
|
|
|
|
|
{
|
|
|
|
|
export RET=0
|
|
|
|
|
|
|
|
|
|
start_listening_and_sending
|
|
|
|
|
|
|
|
|
|
### Scenario 1: Don't manually set active port, just make sure team
|
|
|
|
|
# works.
|
|
|
|
|
save_tcpdump_outputs "${NS2}" test_team2
|
|
|
|
|
did_interface_receive test_team2 "${NS2_IP}"
|
|
|
|
|
check_err $? "Traffic did not reach team interface in NS2."
|
|
|
|
|
clear_tcpdump_outputs test_team2
|
|
|
|
|
|
|
|
|
|
### Scenario 2: Choose active port.
|
|
|
|
|
set_active_port "${NS1}" test_team1 eth1
|
|
|
|
|
set_active_port "${NS2}" test_team2 eth1
|
|
|
|
|
|
|
|
|
|
wait_to_stop_receiving "${NS2}" eth0
|
|
|
|
|
save_tcpdump_outputs "${NS2}" eth0 eth1
|
|
|
|
|
did_interface_receive eth0 "${NS2_IP}"
|
|
|
|
|
check_fail $? "eth0 IS transmitting when inactive"
|
|
|
|
|
did_interface_receive eth1 "${NS2_IP}"
|
|
|
|
|
check_err $? "eth1 not transmitting when active"
|
|
|
|
|
clear_tcpdump_outputs eth0 eth1
|
|
|
|
|
|
|
|
|
|
### Scenario 3: Change active port.
|
|
|
|
|
set_active_port "${NS1}" test_team1 eth0
|
|
|
|
|
set_active_port "${NS2}" test_team2 eth0
|
|
|
|
|
|
|
|
|
|
wait_to_stop_receiving "${NS2}" eth1
|
|
|
|
|
save_tcpdump_outputs "${NS2}" eth0 eth1
|
|
|
|
|
did_interface_receive eth0 "${NS2_IP}"
|
|
|
|
|
check_err $? "eth0 not transmitting when active"
|
|
|
|
|
did_interface_receive eth1 "${NS2_IP}"
|
|
|
|
|
check_fail $? "eth1 IS transmitting when inactive"
|
|
|
|
|
clear_tcpdump_outputs eth0 eth1
|
|
|
|
|
|
|
|
|
|
log_test "teamd active backup runner test"
|
|
|
|
|
|
|
|
|
|
stop_sending_and_listening
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require_command teamd
|
|
|
|
|
require_command teamdctl
|
|
|
|
|
require_command iperf3
|
|
|
|
|
require_command tcpdump
|
|
|
|
|
environment_create activebackup
|
|
|
|
|
tests_run
|
|
|
|
|
exit "${EXIT_STATUS}"
|