| #!/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 |
| } |