1*10407eebSMarc Harvey#!/bin/bash 2*10407eebSMarc Harvey# SPDX-License-Identifier: GPL-2.0 3*10407eebSMarc Harvey 4*10407eebSMarc Harvey# These tests verify that teamd is able to enable and disable ports via the 5*10407eebSMarc Harvey# active backup runner. 6*10407eebSMarc Harvey# 7*10407eebSMarc Harvey# Topology: 8*10407eebSMarc Harvey# 9*10407eebSMarc Harvey# +-------------------------+ NS1 10*10407eebSMarc Harvey# | test_team1 | 11*10407eebSMarc Harvey# | + | 12*10407eebSMarc Harvey# | eth0 | eth1 | 13*10407eebSMarc Harvey# | +---+---+ | 14*10407eebSMarc Harvey# | | | | 15*10407eebSMarc Harvey# +-------------------------+ 16*10407eebSMarc Harvey# | | 17*10407eebSMarc Harvey# +-------------------------+ NS2 18*10407eebSMarc Harvey# | | | | 19*10407eebSMarc Harvey# | +-------+ | 20*10407eebSMarc Harvey# | eth0 | eth1 | 21*10407eebSMarc Harvey# | + | 22*10407eebSMarc Harvey# | test_team2 | 23*10407eebSMarc Harvey# +-------------------------+ 24*10407eebSMarc Harvey 25*10407eebSMarc Harveyexport ALL_TESTS="teamd_test_active_backup" 26*10407eebSMarc Harvey 27*10407eebSMarc Harveytest_dir="$(dirname "$0")" 28*10407eebSMarc Harvey# shellcheck disable=SC1091 29*10407eebSMarc Harveysource "${test_dir}/../../../net/lib.sh" 30*10407eebSMarc Harvey# shellcheck disable=SC1091 31*10407eebSMarc Harveysource "${test_dir}/team_lib.sh" 32*10407eebSMarc Harvey 33*10407eebSMarc HarveyNS1="" 34*10407eebSMarc HarveyNS2="" 35*10407eebSMarc Harveyexport NODAD="nodad" 36*10407eebSMarc HarveyPREFIX_LENGTH="64" 37*10407eebSMarc HarveyNS1_IP="fd00::1" 38*10407eebSMarc HarveyNS2_IP="fd00::2" 39*10407eebSMarc HarveyNS1_IP4="192.168.0.1" 40*10407eebSMarc HarveyNS2_IP4="192.168.0.2" 41*10407eebSMarc HarveyNS1_TEAMD_CONF="" 42*10407eebSMarc HarveyNS2_TEAMD_CONF="" 43*10407eebSMarc HarveyNS1_TEAMD_PID="" 44*10407eebSMarc HarveyNS2_TEAMD_PID="" 45*10407eebSMarc Harvey 46*10407eebSMarc Harveywhile getopts "4" opt; do 47*10407eebSMarc Harvey case $opt in 48*10407eebSMarc Harvey 4) 49*10407eebSMarc Harvey echo "IPv4 mode selected." 50*10407eebSMarc Harvey export NODAD= 51*10407eebSMarc Harvey PREFIX_LENGTH="24" 52*10407eebSMarc Harvey NS1_IP="${NS1_IP4}" 53*10407eebSMarc Harvey NS2_IP="${NS2_IP4}" 54*10407eebSMarc Harvey ;; 55*10407eebSMarc Harvey \?) 56*10407eebSMarc Harvey echo "Invalid option: -${OPTARG}" >&2 57*10407eebSMarc Harvey exit 1 58*10407eebSMarc Harvey ;; 59*10407eebSMarc Harvey esac 60*10407eebSMarc Harveydone 61*10407eebSMarc Harvey 62*10407eebSMarc Harveyteamd_config_create() 63*10407eebSMarc Harvey{ 64*10407eebSMarc Harvey local runner=$1 65*10407eebSMarc Harvey local dev=$2 66*10407eebSMarc Harvey local conf 67*10407eebSMarc Harvey 68*10407eebSMarc Harvey conf=$(mktemp) 69*10407eebSMarc Harvey 70*10407eebSMarc Harvey cat > "${conf}" <<-EOF 71*10407eebSMarc Harvey { 72*10407eebSMarc Harvey "device": "${dev}", 73*10407eebSMarc Harvey "runner": {"name": "${runner}"}, 74*10407eebSMarc Harvey "ports": { 75*10407eebSMarc Harvey "eth0": {}, 76*10407eebSMarc Harvey "eth1": {} 77*10407eebSMarc Harvey } 78*10407eebSMarc Harvey } 79*10407eebSMarc Harvey EOF 80*10407eebSMarc Harvey echo "${conf}" 81*10407eebSMarc Harvey} 82*10407eebSMarc Harvey 83*10407eebSMarc Harvey# Create the network namespaces, veth pair, and team devices in the specified 84*10407eebSMarc Harvey# runner. 85*10407eebSMarc Harvey# Globals: 86*10407eebSMarc Harvey# RET - Used by test infra, set by `check_err` functions. 87*10407eebSMarc Harvey# Arguments: 88*10407eebSMarc Harvey# runner - The Teamd runner to use for the Team devices. 89*10407eebSMarc Harveyenvironment_create() 90*10407eebSMarc Harvey{ 91*10407eebSMarc Harvey local runner=$1 92*10407eebSMarc Harvey 93*10407eebSMarc Harvey echo "Setting up two-link aggregation for runner ${runner}" 94*10407eebSMarc Harvey echo "Teamd version is: $(teamd --version)" 95*10407eebSMarc Harvey trap environment_destroy EXIT 96*10407eebSMarc Harvey 97*10407eebSMarc Harvey setup_ns ns1 ns2 98*10407eebSMarc Harvey NS1="${NS_LIST[0]}" 99*10407eebSMarc Harvey NS2="${NS_LIST[1]}" 100*10407eebSMarc Harvey 101*10407eebSMarc Harvey for link in $(seq 0 1); do 102*10407eebSMarc Harvey ip -n "${NS1}" link add "eth${link}" type veth peer name \ 103*10407eebSMarc Harvey "eth${link}" netns "${NS2}" 104*10407eebSMarc Harvey check_err $? "Failed to create veth pair" 105*10407eebSMarc Harvey done 106*10407eebSMarc Harvey 107*10407eebSMarc Harvey NS1_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team1") 108*10407eebSMarc Harvey NS2_TEAMD_CONF=$(teamd_config_create "${runner}" "test_team2") 109*10407eebSMarc Harvey echo "Conf files are ${NS1_TEAMD_CONF} and ${NS2_TEAMD_CONF}" 110*10407eebSMarc Harvey 111*10407eebSMarc Harvey ip netns exec "${NS1}" teamd -d -f "${NS1_TEAMD_CONF}" 112*10407eebSMarc Harvey check_err $? "Failed to create team device in ${NS1}" 113*10407eebSMarc Harvey NS1_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS1_TEAMD_CONF}") 114*10407eebSMarc Harvey 115*10407eebSMarc Harvey ip netns exec "${NS2}" teamd -d -f "${NS2_TEAMD_CONF}" 116*10407eebSMarc Harvey check_err $? "Failed to create team device in ${NS2}" 117*10407eebSMarc Harvey NS2_TEAMD_PID=$(pgrep -f "teamd -d -f ${NS2_TEAMD_CONF}") 118*10407eebSMarc Harvey 119*10407eebSMarc Harvey echo "Created team devices" 120*10407eebSMarc Harvey echo "Teamd PIDs are ${NS1_TEAMD_PID} and ${NS2_TEAMD_PID}" 121*10407eebSMarc Harvey 122*10407eebSMarc Harvey ip -n "${NS1}" link set test_team1 up 123*10407eebSMarc Harvey check_err $? "Failed to set test_team1 up in ${NS1}" 124*10407eebSMarc Harvey ip -n "${NS2}" link set test_team2 up 125*10407eebSMarc Harvey check_err $? "Failed to set test_team2 up in ${NS2}" 126*10407eebSMarc Harvey 127*10407eebSMarc Harvey ip -n "${NS1}" addr add "${NS1_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \ 128*10407eebSMarc Harvey test_team1 129*10407eebSMarc Harvey check_err $? "Failed to add address to team device in ${NS1}" 130*10407eebSMarc Harvey ip -n "${NS2}" addr add "${NS2_IP}/${PREFIX_LENGTH}" "${NODAD}" dev \ 131*10407eebSMarc Harvey test_team2 132*10407eebSMarc Harvey check_err $? "Failed to add address to team device in ${NS2}" 133*10407eebSMarc Harvey 134*10407eebSMarc Harvey slowwait 2 timeout 0.5 ip netns exec "${NS1}" ping -W 1 -c 1 "${NS2_IP}" 135*10407eebSMarc Harvey} 136*10407eebSMarc Harvey 137*10407eebSMarc Harvey# Tear down the environment: kill teamd and delete network namespaces. 138*10407eebSMarc Harveyenvironment_destroy() 139*10407eebSMarc Harvey{ 140*10407eebSMarc Harvey echo "Tearing down two-link aggregation" 141*10407eebSMarc Harvey 142*10407eebSMarc Harvey rm "${NS1_TEAMD_CONF}" 143*10407eebSMarc Harvey rm "${NS2_TEAMD_CONF}" 144*10407eebSMarc Harvey 145*10407eebSMarc Harvey # First, try graceful teamd teardown. 146*10407eebSMarc Harvey ip netns exec "${NS1}" teamd -k -t test_team1 147*10407eebSMarc Harvey ip netns exec "${NS2}" teamd -k -t test_team2 148*10407eebSMarc Harvey 149*10407eebSMarc Harvey # If teamd can't be killed gracefully, then sigkill. 150*10407eebSMarc Harvey if kill -0 "${NS1_TEAMD_PID}" 2>/dev/null; then 151*10407eebSMarc Harvey echo "Sending sigkill to teamd for test_team1" 152*10407eebSMarc Harvey kill -9 "${NS1_TEAMD_PID}" 153*10407eebSMarc Harvey rm -f /var/run/teamd/test_team1.{pid,sock} 154*10407eebSMarc Harvey fi 155*10407eebSMarc Harvey if kill -0 "${NS2_TEAMD_PID}" 2>/dev/null; then 156*10407eebSMarc Harvey echo "Sending sigkill to teamd for test_team2" 157*10407eebSMarc Harvey kill -9 "${NS2_TEAMD_PID}" 158*10407eebSMarc Harvey rm -f /var/run/teamd/test_team2.{pid,sock} 159*10407eebSMarc Harvey fi 160*10407eebSMarc Harvey cleanup_all_ns 161*10407eebSMarc Harvey} 162*10407eebSMarc Harvey 163*10407eebSMarc Harvey# Change the active port for an active-backup mode team. 164*10407eebSMarc Harvey# Arguments: 165*10407eebSMarc Harvey# namespace - The network namespace that the team is in. 166*10407eebSMarc Harvey# team - The name of the team. 167*10407eebSMarc Harvey# active_port - The port to make active. 168*10407eebSMarc Harveyset_active_port() 169*10407eebSMarc Harvey{ 170*10407eebSMarc Harvey local namespace=$1 171*10407eebSMarc Harvey local team=$2 172*10407eebSMarc Harvey local active_port=$3 173*10407eebSMarc Harvey 174*10407eebSMarc Harvey ip netns exec "${namespace}" teamdctl "${team}" state item set \ 175*10407eebSMarc Harvey runner.active_port "${active_port}" 176*10407eebSMarc Harvey slowwait 2 bash -c "ip netns exec ${namespace} teamdctl ${team} state \ 177*10407eebSMarc Harvey item get runner.active_port | grep -q ${active_port}" 178*10407eebSMarc Harvey} 179*10407eebSMarc Harvey 180*10407eebSMarc Harvey# Wait for an interface to stop receiving traffic. If it keeps receiving traffic 181*10407eebSMarc Harvey# for the duration of the timeout, then return an error. 182*10407eebSMarc Harvey# Arguments: 183*10407eebSMarc Harvey# - namespace - The network namespace that the interface is in. 184*10407eebSMarc Harvey# - interface - The name of the interface. 185*10407eebSMarc Harveywait_to_stop_receiving() 186*10407eebSMarc Harvey{ 187*10407eebSMarc Harvey local namespace=$1 188*10407eebSMarc Harvey local interface=$2 189*10407eebSMarc Harvey 190*10407eebSMarc Harvey echo "Waiting for ${interface} in ${namespace} to stop receiving" 191*10407eebSMarc Harvey slowwait 10 check_no_traffic "${interface}" "${NS2_IP}" \ 192*10407eebSMarc Harvey "${namespace}" 193*10407eebSMarc Harvey} 194*10407eebSMarc Harvey 195*10407eebSMarc Harvey# Test that active backup runner can change active ports. 196*10407eebSMarc Harvey# Globals: 197*10407eebSMarc Harvey# RET - Used by test infra, set by `check_err` functions. 198*10407eebSMarc Harveyteamd_test_active_backup() 199*10407eebSMarc Harvey{ 200*10407eebSMarc Harvey export RET=0 201*10407eebSMarc Harvey 202*10407eebSMarc Harvey start_listening_and_sending 203*10407eebSMarc Harvey 204*10407eebSMarc Harvey ### Scenario 1: Don't manually set active port, just make sure team 205*10407eebSMarc Harvey # works. 206*10407eebSMarc Harvey save_tcpdump_outputs "${NS2}" test_team2 207*10407eebSMarc Harvey did_interface_receive test_team2 "${NS2_IP}" 208*10407eebSMarc Harvey check_err $? "Traffic did not reach team interface in NS2." 209*10407eebSMarc Harvey clear_tcpdump_outputs test_team2 210*10407eebSMarc Harvey 211*10407eebSMarc Harvey ### Scenario 2: Choose active port. 212*10407eebSMarc Harvey set_active_port "${NS1}" test_team1 eth1 213*10407eebSMarc Harvey set_active_port "${NS2}" test_team2 eth1 214*10407eebSMarc Harvey 215*10407eebSMarc Harvey wait_to_stop_receiving "${NS2}" eth0 216*10407eebSMarc Harvey save_tcpdump_outputs "${NS2}" eth0 eth1 217*10407eebSMarc Harvey did_interface_receive eth0 "${NS2_IP}" 218*10407eebSMarc Harvey check_fail $? "eth0 IS transmitting when inactive" 219*10407eebSMarc Harvey did_interface_receive eth1 "${NS2_IP}" 220*10407eebSMarc Harvey check_err $? "eth1 not transmitting when active" 221*10407eebSMarc Harvey clear_tcpdump_outputs eth0 eth1 222*10407eebSMarc Harvey 223*10407eebSMarc Harvey ### Scenario 3: Change active port. 224*10407eebSMarc Harvey set_active_port "${NS1}" test_team1 eth0 225*10407eebSMarc Harvey set_active_port "${NS2}" test_team2 eth0 226*10407eebSMarc Harvey 227*10407eebSMarc Harvey wait_to_stop_receiving "${NS2}" eth1 228*10407eebSMarc Harvey save_tcpdump_outputs "${NS2}" eth0 eth1 229*10407eebSMarc Harvey did_interface_receive eth0 "${NS2_IP}" 230*10407eebSMarc Harvey check_err $? "eth0 not transmitting when active" 231*10407eebSMarc Harvey did_interface_receive eth1 "${NS2_IP}" 232*10407eebSMarc Harvey check_fail $? "eth1 IS transmitting when inactive" 233*10407eebSMarc Harvey clear_tcpdump_outputs eth0 eth1 234*10407eebSMarc Harvey 235*10407eebSMarc Harvey log_test "teamd active backup runner test" 236*10407eebSMarc Harvey 237*10407eebSMarc Harvey stop_sending_and_listening 238*10407eebSMarc Harvey} 239*10407eebSMarc Harvey 240*10407eebSMarc Harveyrequire_command teamd 241*10407eebSMarc Harveyrequire_command teamdctl 242*10407eebSMarc Harveyrequire_command iperf3 243*10407eebSMarc Harveyrequire_command tcpdump 244*10407eebSMarc Harveyenvironment_create activebackup 245*10407eebSMarc Harveytests_run 246*10407eebSMarc Harveyexit "${EXIT_STATUS}" 247