Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for net selftests
TEST_PROGS := \
decoupled_enablement.sh \
dev_addr_lists.sh \
non_ether_header_ops.sh \
options.sh \
propagation.sh \
refleak.sh \
teamd_activebackup.sh \
transmit_failover.sh \
# end of TEST_PROGS
TEST_INCLUDES := \
team_lib.sh \
../bonding/lag_lib.sh \
../../../net/forwarding/lib.sh \
../../../net/in_netns.sh \
../../../net/lib.sh \
../../../net/lib/sh/defer.sh \
# end of TEST_INCLUDES
include ../../../lib.mk
@@ -0,0 +1,13 @@
CONFIG_BONDING=y
CONFIG_DUMMY=y
CONFIG_IPV6=y
CONFIG_MACVLAN=y
CONFIG_NETDEVSIM=m
CONFIG_NET_IPGRE=y
CONFIG_NET_TEAM=y
CONFIG_NET_TEAM_MODE_ACTIVEBACKUP=y
CONFIG_NET_TEAM_MODE_BROADCAST=y
CONFIG_NET_TEAM_MODE_LOADBALANCE=y
CONFIG_NET_TEAM_MODE_RANDOM=y
CONFIG_NET_TEAM_MODE_ROUNDROBIN=y
CONFIG_VETH=y
@@ -0,0 +1,249 @@
#!/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}"
@@ -0,0 +1,49 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# Test team device handling of addr lists (dev->uc, mc)
#
ALL_TESTS="
team_cleanup
"
REQUIRE_MZ=no
NUM_NETIFS=0
lib_dir=$(dirname "$0")
source "$lib_dir"/../../../net/forwarding/lib.sh
source "$lib_dir"/../bonding/lag_lib.sh
destroy()
{
local ifnames=(dummy1 dummy2 team0 mv0)
local ifname
for ifname in "${ifnames[@]}"; do
ip link del "$ifname" &>/dev/null
done
}
cleanup()
{
pre_cleanup
destroy
}
team_cleanup()
{
RET=0
test_LAG_cleanup "team" "lacp"
}
trap cleanup EXIT
tests_run
exit "$EXIT_STATUS"
@@ -0,0 +1,41 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# shellcheck disable=SC2154
#
# Reproduce the non-Ethernet header_ops confusion scenario with:
# g0 (gre) -> b0 (bond) -> t0 (team)
#
# Before the fix, direct header_ops inheritance in this stack could call
# callbacks with the wrong net_device context and crash.
lib_dir=$(dirname "$0")
source "$lib_dir"/../../../net/lib.sh
trap cleanup_all_ns EXIT
setup_ns ns1
ip -n "$ns1" link add d0 type dummy
ip -n "$ns1" addr add 10.10.10.1/24 dev d0
ip -n "$ns1" link set d0 up
ip -n "$ns1" link add g0 type gre local 10.10.10.1
ip -n "$ns1" link add b0 type bond mode active-backup
ip -n "$ns1" link add t0 type team
ip -n "$ns1" link set g0 master b0
ip -n "$ns1" link set b0 master t0
ip -n "$ns1" link set g0 up
ip -n "$ns1" link set b0 up
ip -n "$ns1" link set t0 up
# IPv6 address assignment triggers MLD join reports that call
# dev_hard_header() on t0, exercising the inherited header_ops path.
ip -n "$ns1" -6 addr add 2001:db8:1::1/64 dev t0 nodad
for i in $(seq 1 20); do
ip netns exec "$ns1" ping -6 -I t0 ff02::1 -c1 -W1 &>/dev/null || true
done
echo "PASS: non-Ethernet header_ops stacking did not crash"
exit "$EXIT_STATUS"
@@ -0,0 +1,285 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# These tests verify basic set and get functionality of the team
# driver options over netlink.
# Run in private netns.
test_dir="$(dirname "$0")"
if [[ $# -eq 0 ]]; then
"${test_dir}"/../../../net/in_netns.sh "$0" __subprocess
exit $?
fi
export ALL_TESTS="
team_test_options
team_test_enabled_implicit_changes
team_test_rx_enabled_implicit_changes
team_test_tx_enabled_implicit_changes
"
# shellcheck disable=SC1091
source "${test_dir}/../../../net/lib.sh"
TEAM_PORT="team0"
MEMBER_PORT="dummy0"
setup()
{
ip link add name "${MEMBER_PORT}" type dummy
ip link add name "${TEAM_PORT}" type team
}
get_and_check_value()
{
local option_name="$1"
local expected_value="$2"
local port_flag="$3"
local value_from_get
if ! value_from_get=$(teamnl "${TEAM_PORT}" getoption "${option_name}" \
"${port_flag}"); then
echo "Could not get option '${option_name}'" >&2
return 1
fi
if [[ "${value_from_get}" != "${expected_value}" ]]; then
echo "Incorrect value for option '${option_name}'" >&2
echo "get (${value_from_get}) != set (${expected_value})" >&2
return 1
fi
}
set_and_check_get()
{
local option_name="$1"
local option_value="$2"
local port_flag="$3"
local value_from_get
if ! teamnl "${TEAM_PORT}" setoption "${option_name}" \
"${option_value}" "${port_flag}"; then
echo "'setoption ${option_name} ${option_value}' failed" >&2
return 1
fi
get_and_check_value "${option_name}" "${option_value}" "${port_flag}"
return $?
}
# Get a "port flag" to pass to the `teamnl` command.
# E.g. $1="dummy0" -> "port=dummy0",
# $1="" -> ""
get_port_flag()
{
local port_name="$1"
if [[ -n "${port_name}" ]]; then
echo "--port=${port_name}"
fi
}
attach_port_if_specified()
{
local port_name="$1"
if [[ -n "${port_name}" ]]; then
ip link set dev "${port_name}" master "${TEAM_PORT}"
return $?
fi
}
detach_port_if_specified()
{
local port_name="$1"
if [[ -n "${port_name}" ]]; then
ip link set dev "${port_name}" nomaster
return $?
fi
}
# Test that an option's get value matches its set value.
# Globals:
# RET - Used by testing infra like `check_err`.
# EXIT_STATUS - Used by `log_test` for whole script exit value.
# Arguments:
# option_name - The name of the option.
# value_1 - The first value to try setting.
# value_2 - The second value to try setting.
# port_name - The (optional) name of the attached port.
team_test_option()
{
local option_name="$1"
local value_1="$2"
local value_2="$3"
local possible_values="$2 $3 $2"
local port_name="$4"
local port_flag
RET=0
echo "Setting '${option_name}' to '${value_1}' and '${value_2}'"
attach_port_if_specified "${port_name}"
check_err $? "Couldn't attach ${port_name} to master"
port_flag=$(get_port_flag "${port_name}")
# Set and get both possible values.
for value in ${possible_values}; do
set_and_check_get "${option_name}" "${value}" "${port_flag}"
check_err $? "Failed to set '${option_name}' to '${value}'"
done
detach_port_if_specified "${port_name}"
check_err $? "Couldn't detach ${port_name} from its master"
log_test "Set + Get '${option_name}' test"
}
# Test that getting a non-existant option fails.
# Globals:
# RET - Used by testing infra like `check_err`.
# EXIT_STATUS - Used by `log_test` for whole script exit value.
# Arguments:
# option_name - The name of the option.
# port_name - The (optional) name of the attached port.
team_test_get_option_fails()
{
local option_name="$1"
local port_name="$2"
local port_flag
RET=0
attach_port_if_specified "${port_name}"
check_err $? "Couldn't attach ${port_name} to master"
port_flag=$(get_port_flag "${port_name}")
# Just confirm that getting the value fails.
teamnl "${TEAM_PORT}" getoption "${option_name}" "${port_flag}"
check_fail $? "Shouldn't be able to get option '${option_name}'"
detach_port_if_specified "${port_name}"
log_test "Get '${option_name}' fails"
}
team_test_options()
{
# Wrong option name behavior.
team_test_get_option_fails fake_option1
team_test_get_option_fails fake_option2 "${MEMBER_PORT}"
# Correct set and get behavior.
team_test_option mode activebackup loadbalance
team_test_option notify_peers_count 0 5
team_test_option notify_peers_interval 0 5
team_test_option mcast_rejoin_count 0 5
team_test_option mcast_rejoin_interval 0 5
team_test_option enabled true false "${MEMBER_PORT}"
team_test_option rx_enabled true false "${MEMBER_PORT}"
team_test_option tx_enabled true false "${MEMBER_PORT}"
team_test_option user_linkup true false "${MEMBER_PORT}"
team_test_option user_linkup_enabled true false "${MEMBER_PORT}"
team_test_option priority 10 20 "${MEMBER_PORT}"
team_test_option queue_id 0 1 "${MEMBER_PORT}"
}
team_test_enabled_implicit_changes()
{
export RET=0
attach_port_if_specified "${MEMBER_PORT}"
check_err $? "Couldn't attach ${MEMBER_PORT} to master"
# Set enabled to true.
set_and_check_get enabled true "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'enabled' to true"
# Show that both rx enabled and tx enabled are true.
get_and_check_value rx_enabled true "--port=${MEMBER_PORT}"
check_err $? "'Rx_enabled' wasn't implicitly set to true"
get_and_check_value tx_enabled true "--port=${MEMBER_PORT}"
check_err $? "'Tx_enabled' wasn't implicitly set to true"
# Set enabled to false.
set_and_check_get enabled false "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'enabled' to false"
# Show that both rx enabled and tx enabled are false.
get_and_check_value rx_enabled false "--port=${MEMBER_PORT}"
check_err $? "'Rx_enabled' wasn't implicitly set to false"
get_and_check_value tx_enabled false "--port=${MEMBER_PORT}"
check_err $? "'Tx_enabled' wasn't implicitly set to false"
log_test "'Enabled' implicit changes"
}
team_test_rx_enabled_implicit_changes()
{
export RET=0
attach_port_if_specified "${MEMBER_PORT}"
check_err $? "Couldn't attach ${MEMBER_PORT} to master"
# Set enabled to true.
set_and_check_get enabled true "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'enabled' to true"
# Set rx_enabled to false.
set_and_check_get rx_enabled false "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'rx_enabled' to false"
# Show that enabled is false.
get_and_check_value enabled false "--port=${MEMBER_PORT}"
check_err $? "'enabled' wasn't implicitly set to false"
# Set rx_enabled to true.
set_and_check_get rx_enabled true "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'rx_enabled' to true"
# Show that enabled is true.
get_and_check_value enabled true "--port=${MEMBER_PORT}"
check_err $? "'enabled' wasn't implicitly set to true"
log_test "'Rx_enabled' implicit changes"
}
team_test_tx_enabled_implicit_changes()
{
export RET=0
attach_port_if_specified "${MEMBER_PORT}"
check_err $? "Couldn't attach ${MEMBER_PORT} to master"
# Set enabled to true.
set_and_check_get enabled true "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'enabled' to true"
# Set tx_enabled to false.
set_and_check_get tx_enabled false "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'tx_enabled' to false"
# Show that enabled is false.
get_and_check_value enabled false "--port=${MEMBER_PORT}"
check_err $? "'enabled' wasn't implicitly set to false"
# Set tx_enabled to true.
set_and_check_get tx_enabled true "--port=${MEMBER_PORT}"
check_err $? "Failed to set 'tx_enabled' to true"
# Show that enabled is true.
get_and_check_value enabled true "--port=${MEMBER_PORT}"
check_err $? "'enabled' wasn't implicitly set to true"
log_test "'Tx_enabled' implicit changes"
}
require_command teamnl
setup
tests_run
exit "${EXIT_STATUS}"
@@ -0,0 +1,80 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
set -e
NSIM_LRO_ID=$((256 + RANDOM % 256))
NSIM_LRO_SYS=/sys/bus/netdevsim/devices/netdevsim$NSIM_LRO_ID
NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device
NSIM_DEV_SYS_DEL=/sys/bus/netdevsim/del_device
cleanup()
{
set +e
ip link del dummyteam &>/dev/null
ip link del team0 &>/dev/null
echo $NSIM_LRO_ID > $NSIM_DEV_SYS_DEL
modprobe -r netdevsim
}
# Trigger LRO propagation to the lower.
# https://lore.kernel.org/netdev/aBvOpkIoxcr9PfDg@mini-arch/
team_lro()
{
# using netdevsim because it supports NETIF_F_LRO
NSIM_LRO_NAME=$(find $NSIM_LRO_SYS/net -maxdepth 1 -type d ! \
-path $NSIM_LRO_SYS/net -exec basename {} \;)
ip link add name team0 type team
ip link set $NSIM_LRO_NAME down
ip link set dev $NSIM_LRO_NAME master team0
ip link set team0 up
ethtool -K team0 large-receive-offload off
ip link del team0
}
# Trigger promisc propagation to the lower during IFLA_MASTER.
# https://lore.kernel.org/netdev/20250506032328.3003050-1-sdf@fomichev.me/
team_promisc()
{
ip link add name dummyteam type dummy
ip link add name team0 type team
ip link set dummyteam down
ip link set team0 promisc on
ip link set dev dummyteam master team0
ip link set team0 up
ip link del team0
ip link del dummyteam
}
# Trigger promisc propagation to the lower via netif_change_flags (aka
# ndo_change_rx_flags).
# https://lore.kernel.org/netdev/20250514220319.3505158-1-stfomichev@gmail.com/
team_change_flags()
{
ip link add name dummyteam type dummy
ip link add name team0 type team
ip link set dummyteam down
ip link set dev dummyteam master team0
ip link set team0 up
ip link set team0 promisc on
# Make sure we can add more L2 addresses without any issues.
ip link add link team0 address 00:00:00:00:00:01 team0.1 type macvlan
ip link set team0.1 up
ip link del team0.1
ip link del team0
ip link del dummyteam
}
trap cleanup EXIT
modprobe netdevsim || :
echo $NSIM_LRO_ID > $NSIM_DEV_SYS_NEW
udevadm settle
team_lro
team_promisc
team_change_flags
@@ -0,0 +1,17 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# shellcheck disable=SC2154
lib_dir=$(dirname "$0")
source "$lib_dir"/../../../net/lib.sh
trap cleanup_all_ns EXIT
# Test that there is no reference count leak and that dummy1 can be deleted.
# https://lore.kernel.org/netdev/4d69abe1-ca8d-4f0b-bcf8-13899b211e57@I-love.SAKURA.ne.jp/
setup_ns ns1 ns2
ip -n "$ns1" link add name team1 type team
ip -n "$ns1" link add name dummy1 mtu 1499 type dummy
ip -n "$ns1" link set dev dummy1 master team1
ip -n "$ns1" link set dev dummy1 netns "$ns2"
ip -n "$ns2" link del dev dummy1
@@ -0,0 +1 @@
timeout=300
@@ -0,0 +1,174 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
test_dir="$(dirname "$0")"
export REQUIRE_MZ=no
export NUM_NETIFS=0
# shellcheck disable=SC1091
source "${test_dir}/../../../net/forwarding/lib.sh"
TCP_PORT="43434"
# Create a team interface inside of a given network namespace with a given
# mode, members, and IP address.
# Arguments:
# namespace - Network namespace to put the team interface into.
# team - The name of the team interface to setup.
# mode - The team mode of the interface.
# ip_address - The IP address to assign to the team interface.
# prefix_length - The prefix length for the IP address subnet.
# $@ - members - The member interfaces of the aggregation.
setup_team()
{
local namespace=$1
local team=$2
local mode=$3
local ip_address=$4
local prefix_length=$5
shift 5
local members=("$@")
# Prerequisite: team must have no members
for member in "${members[@]}"; do
ip -n "${namespace}" link set "${member}" nomaster
done
# Prerequisite: team must have no address in order to set it
# shellcheck disable=SC2086
ip -n "${namespace}" addr del "${ip_address}/${prefix_length}" \
${NODAD} dev "${team}"
echo "Setting team in ${namespace} to mode ${mode}"
if ! ip -n "${namespace}" link set "${team}" down; then
echo "Failed to bring team device down"
return 1
fi
if ! ip netns exec "${namespace}" teamnl "${team}" setoption mode \
"${mode}"; then
echo "Failed to set ${team} mode to '${mode}'"
return 1
fi
# Aggregate the members into teams.
for member in "${members[@]}"; do
ip -n "${namespace}" link set "${member}" master "${team}"
done
# Bring team devices up and give them addresses.
if ! ip -n "${namespace}" link set "${team}" up; then
echo "Failed to set ${team} up"
return 1
fi
# shellcheck disable=SC2086
if ! ip -n "${namespace}" addr add "${ip_address}/${prefix_length}" \
${NODAD} dev "${team}"; then
echo "Failed to give ${team} IP address in ${namespace}"
return 1
fi
}
# This is global used to keep track of the sender's iperf3 process, so that it
# can be terminated.
declare sender_pid
# Start sending and receiving TCP traffic with iperf3.
# Globals:
# sender_pid - The process ID of the iperf3 sender process. Used to kill it
# later.
start_listening_and_sending()
{
ip netns exec "${NS2}" iperf3 -s -p "${TCP_PORT}" --logfile /dev/null &
# Wait for server to become reachable before starting client.
slowwait 5 ip netns exec "${NS1}" iperf3 -c "${NS2_IP}" -p \
"${TCP_PORT}" -t 1 --logfile /dev/null
ip netns exec "${NS1}" iperf3 -c "${NS2_IP}" -p "${TCP_PORT}" -b 1M -l \
1K -t 0 --logfile /dev/null &
sender_pid=$!
}
# Stop sending TCP traffic with iperf3.
# Globals:
# sender_pid - The process ID of the iperf3 sender process.
stop_sending_and_listening()
{
kill "${sender_pid}" && wait "${sender_pid}" 2>/dev/null || true
}
# Monitor for TCP traffic with Tcpdump, save results to temp files.
# Arguments:
# namespace - The network namespace to run tcpdump inside of.
# $@ - interfaces - The interfaces to listen to.
save_tcpdump_outputs()
{
local namespace=$1
shift 1
local interfaces=("$@")
for interface in "${interfaces[@]}"; do
tcpdump_start "${interface}" "${namespace}"
done
sleep 1
for interface in "${interfaces[@]}"; do
tcpdump_stop_nosleep "${interface}"
done
}
clear_tcpdump_outputs()
{
local interfaces=("$@")
for interface in "${interfaces[@]}"; do
tcpdump_cleanup "${interface}"
done
}
# Read Tcpdump output, determine packet counts.
# Arguments:
# interface - The name of the interface to count packets for.
# ip_address - The destination IP address.
did_interface_receive()
{
local interface="$1"
local ip_address="$2"
local packet_count
packet_count=$(tcpdump_show "$interface" | grep -c \
"> ${ip_address}.${TCP_PORT}")
echo "Packet count for ${interface} was ${packet_count}"
if [[ "${packet_count}" -gt 0 ]]; then
true
else
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
}
@@ -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}"
@@ -0,0 +1,158 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# These tests verify the basic failover capability of the team driver via the
# `enabled` team driver option across different team driver modes. This does not
# rely on teamd, and instead just uses teamnl to set the `enabled` option
# directly.
#
# Topology:
#
# +-------------------------+ NS1
# | test_team1 |
# | + |
# | eth0 | eth1 |
# | +---+---+ |
# | | | |
# +-------------------------+
# | |
# +-------------------------+ NS2
# | | | |
# | +-------+ |
# | eth0 | eth1 |
# | + |
# | test_team2 |
# +-------------------------+
export ALL_TESTS="team_test_failover"
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" "eth1")
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
# 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 eth1 type veth peer name eth1 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[@]}"
}
# Check that failover works for a specific team driver 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_failover()
{
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"
start_listening_and_sending
### Scenario 1: All interfaces initially enabled.
save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
did_interface_receive eth0 "${NS2_IP}"
check_err $? "eth0 not transmitting when both links enabled"
did_interface_receive eth1 "${NS2_IP}"
check_err $? "eth1 not transmitting when both links enabled"
clear_tcpdump_outputs "${MEMBERS[@]}"
### Scenario 2: One tx-side interface disabled.
ip netns exec "${NS1}" teamnl test_team1 setoption enabled false \
--port=eth1
slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \
enabled --port=eth1 | grep -q false"
save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
did_interface_receive eth0 "${NS2_IP}"
check_err $? "eth0 not transmitting when enabled"
did_interface_receive eth1 "${NS2_IP}"
check_fail $? "eth1 IS transmitting when disabled"
clear_tcpdump_outputs "${MEMBERS[@]}"
### Scenario 3: The interface is re-enabled.
ip netns exec "${NS1}" teamnl test_team1 setoption enabled true \
--port=eth1
slowwait 2 bash -c "ip netns exec ${NS1} teamnl test_team1 getoption \
enabled --port=eth1 | grep -q true"
save_tcpdump_outputs "${NS2}" "${MEMBERS[@]}"
did_interface_receive eth0 "${NS2_IP}"
check_err $? "eth0 not transmitting when both links enabled"
did_interface_receive eth1 "${NS2_IP}"
check_err $? "eth1 not transmitting when both links enabled"
clear_tcpdump_outputs "${MEMBERS[@]}"
log_test "Failover of '${mode}' test"
# Clean up
stop_sending_and_listening
}
team_test_failover()
{
team_test_mode_failover broadcast
team_test_mode_failover roundrobin
team_test_mode_failover random
# Don't test `activebackup` or `loadbalance` modes, since they are too
# complicated for just setting `enabled` to work. They use more than
# the `enabled` option for transmit.
}
require_command teamnl
require_command iperf3
require_command tcpdump
environment_create
tests_run
exit "${EXIT_STATUS}"