Re: [PATCH net-next v7 05/10] selftests: net: Add test for enablement of ports with teamd

Paolo Abeni
2026-04-13T13:07:50Z

On 4/9/26 4:59 AM, Marc Harvey wrote:
> There are no tests that verify enablement and disablement of team driver
> ports with teamd. This should work even with changes to the enablement
> option, so it is important to test.
>
> This test sets up an active-backup network configuration across two
> network namespaces, and tries to send traffic while changing which
> link is the active one.
>
> Also increase the team test timeout to 300 seconds, because gracefully
> killing teamd can take 30 seconds for each instance.
>
> Signed-off-by: Marc Harvey <marcharvey@google.com>
> ---
> Changes in v7:
> - Increase test timeout to 300 seconds, since terminating teamd can
> take 30 seconds during test cleanup.
> - Link to v6: https://lore.kernel.org/netdev/20260408-teaming-driver-internal-v6-5-e5bcdcf72504@google.com/
>
> Changes in v6:
> - Remove manual changing of member port states to UP, not needed.
> - Link to v5: https://lore.kernel.org/netdev/20260406-teaming-driver-internal-v5-5-e8a3f348a1c5@google.com/
>
> Changes in v5:
> - Make test wait for inactive link to stop receiving traffic after
> setting it to inactive, since there was a race condition.
> - Change test teardown to try graceful shutdown first, then use
> sigkill if needed.
> - Manually delete leftover teamd files during teardown.
> - Use tcpdump instead of checking rx counters.
> - Link to v4: https://lore.kernel.org/netdev/20260403-teaming-driver-internal-v4-5-d3032f33ca25@google.com/
>
> Changed in v3:
> - Make test cleanup kill teamd instead of terminate.
> - Link to v2: https://lore.kernel.org/netdev/20260401-teaming-driver-internal-v2-5-f80c1291727b@google.com/
>
> Changes in v2:
> - Fix shellcheck failures.
> - Remove dependency on net forwarding lib and pipe viewer tools.
> - Use iperf3 for tcp instead of netcat.
> - Link to v1: https://lore.kernel.org/all/20260331053353.2504254-6-marcharvey@google.com/
> ---
> tools/testing/selftests/drivers/net/team/Makefile | 1 +
> tools/testing/selftests/drivers/net/team/settings | 1 +
> .../testing/selftests/drivers/net/team/team_lib.sh | 26 +++
> .../drivers/net/team/teamd_activebackup.sh | 246 +++++++++++++++++++++
> tools/testing/selftests/net/lib.sh | 13 ++
> 5 files changed, 287 insertions(+)
>
> diff --git a/tools/testing/selftests/drivers/net/team/Makefile b/tools/testing/selftests/drivers/net/team/Makefile
> index 777da2e0429e..dab922d7f83d 100644
> --- a/tools/testing/selftests/drivers/net/team/Makefile
> +++ b/tools/testing/selftests/drivers/net/team/Makefile
> @@ -7,6 +7,7 @@ TEST_PROGS := \
> options.sh \
> propagation.sh \
> refleak.sh \
> + teamd_activebackup.sh \
> transmit_failover.sh \
> # end of TEST_PROGS
>
> diff --git a/tools/testing/selftests/drivers/net/team/settings b/tools/testing/selftests/drivers/net/team/settings
> new file mode 100644
> index 000000000000..694d70710ff0
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/net/team/settings
> @@ -0,0 +1 @@
> +timeout=300
> diff --git a/tools/testing/selftests/drivers/net/team/team_lib.sh b/tools/testing/selftests/drivers/net/team/team_lib.sh
> index 2057f5edee79..02ef0ee02d6a 100644
> --- a/tools/testing/selftests/drivers/net/team/team_lib.sh
> +++ b/tools/testing/selftests/drivers/net/team/team_lib.sh
> @@ -146,3 +146,29 @@ did_interface_receive()
> false
> fi
> }
> +
> +# Return true if the given interface in the given namespace does NOT receive
> +# traffic over a 1 second period.
> +# Arguments:
> +# interface - The name of the interface.
> +# ip_address - The destination IP address.
> +# namespace - The name of the namespace that the interface is in.
> +check_no_traffic()
> +{
> + local interface="$1"
> + local ip_address="$2"
> + local namespace="$3"
> + local rc
> +
> + save_tcpdump_outputs "${namespace}" "${interface}"
> + did_interface_receive "${interface}" "${ip_address}"
> + rc=$?
> +
> + clear_tcpdump_outputs "${interface}"
> +
> + if [[ "${rc}" -eq 0 ]]; then
> + return 1
> + else
> + return 0
> + fi
> +}
> diff --git a/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh b/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
> new file mode 100755
> index 000000000000..2b26a697e179
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/net/team/teamd_activebackup.sh
> @@ -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

Note for a possible follow-up: it looks like that the above will fail with:

Error: either "local" is duplicate, or "" is garbage.

when running in ipv4 mode (not invoked by the CI/self-test infra), due
to the quotes around ${NODAD}.

/P