Files
linux/tools/testing/selftests/net/hsr/link_faults.sh
Felix Maurer bbbd531faa selftests: hsr: Add more link fault tests for HSR
Run the packet loss and reordering tests also for both HSR versions. Now
they can be removed from the hsr_ping tests completely. The timeout needs
to be increased because there are 15 link fault test cases now, with each
of them taking 5-6sec for the test and at most 5sec for the HSR node tables
to get merged and we also want some room to make the test runs stable.

Signed-off-by: Felix Maurer <fmaurer@redhat.com>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/eb6f667d3804ce63d86f0ee3fbc0e0ac9e1a209a.1770299429.git.fmaurer@redhat.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2026-02-10 12:02:29 +01:00

379 lines
7.7 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# shellcheck disable=SC2329
source ../lib.sh
ALL_TESTS="
test_clean_hsrv0
test_cut_link_hsrv0
test_packet_loss_hsrv0
test_high_packet_loss_hsrv0
test_reordering_hsrv0
test_clean_hsrv1
test_cut_link_hsrv1
test_packet_loss_hsrv1
test_high_packet_loss_hsrv1
test_reordering_hsrv1
test_clean_prp
test_cut_link_prp
test_packet_loss_prp
test_high_packet_loss_prp
test_reordering_prp
"
# The tests are running ping for 5sec with a relatively short interval in
# different scenarios with faulty links (cut links, packet loss, delay,
# reordering) that should be recoverable by HSR/PRP. The ping interval (10ms)
# is short enough that the base delay (50ms) leads to a queue in the netem
# qdiscs which is needed for reordering.
setup_hsr_topo()
{
# Three HSR nodes in a ring, every node has a LAN A interface connected
# to the LAN B interface of the next node.
#
# node1 node2
#
# vethA -------- vethB
# hsr1 hsr2
# vethB vethA
# \ /
# vethA vethB
# hsr3
#
# node3
local ver="$1"
setup_ns node1 node2 node3
# veth links
# shellcheck disable=SC2154 # variables assigned by setup_ns
ip link add vethA netns "$node1" type veth peer name vethB netns "$node2"
# shellcheck disable=SC2154 # variables assigned by setup_ns
ip link add vethA netns "$node2" type veth peer name vethB netns "$node3"
ip link add vethA netns "$node3" type veth peer name vethB netns "$node1"
# MAC addresses (not needed for HSR operation, but helps with debugging)
ip -net "$node1" link set address 00:11:22:00:01:01 dev vethA
ip -net "$node1" link set address 00:11:22:00:01:02 dev vethB
ip -net "$node2" link set address 00:11:22:00:02:01 dev vethA
ip -net "$node2" link set address 00:11:22:00:02:02 dev vethB
ip -net "$node3" link set address 00:11:22:00:03:01 dev vethA
ip -net "$node3" link set address 00:11:22:00:03:02 dev vethB
# HSR interfaces
ip -net "$node1" link add name hsr1 type hsr proto 0 version "$ver" \
slave1 vethA slave2 vethB supervision 45
ip -net "$node2" link add name hsr2 type hsr proto 0 version "$ver" \
slave1 vethA slave2 vethB supervision 45
ip -net "$node3" link add name hsr3 type hsr proto 0 version "$ver" \
slave1 vethA slave2 vethB supervision 45
# IP addresses
ip -net "$node1" addr add 100.64.0.1/24 dev hsr1
ip -net "$node2" addr add 100.64.0.2/24 dev hsr2
ip -net "$node3" addr add 100.64.0.3/24 dev hsr3
# Set all links up
ip -net "$node1" link set vethA up
ip -net "$node1" link set vethB up
ip -net "$node1" link set hsr1 up
ip -net "$node2" link set vethA up
ip -net "$node2" link set vethB up
ip -net "$node2" link set hsr2 up
ip -net "$node3" link set vethA up
ip -net "$node3" link set vethB up
ip -net "$node3" link set hsr3 up
}
setup_prp_topo()
{
# Two PRP nodes, connected by two links (treated as LAN A and LAN B).
#
# vethA ----- vethA
# prp1 prp2
# vethB ----- vethB
#
# node1 node2
setup_ns node1 node2
# veth links
ip link add vethA netns "$node1" type veth peer name vethA netns "$node2"
ip link add vethB netns "$node1" type veth peer name vethB netns "$node2"
# MAC addresses will be copied from LAN A interface
ip -net "$node1" link set address 00:11:22:00:00:01 dev vethA
ip -net "$node2" link set address 00:11:22:00:00:02 dev vethA
# PRP interfaces
ip -net "$node1" link add name prp1 type hsr \
slave1 vethA slave2 vethB supervision 45 proto 1
ip -net "$node2" link add name prp2 type hsr \
slave1 vethA slave2 vethB supervision 45 proto 1
# IP addresses
ip -net "$node1" addr add 100.64.0.1/24 dev prp1
ip -net "$node2" addr add 100.64.0.2/24 dev prp2
# All links up
ip -net "$node1" link set vethA up
ip -net "$node1" link set vethB up
ip -net "$node1" link set prp1 up
ip -net "$node2" link set vethA up
ip -net "$node2" link set vethB up
ip -net "$node2" link set prp2 up
}
wait_for_hsr_node_table()
{
log_info "Wait for node table entries to be merged."
WAIT=5
while [ "${WAIT}" -gt 0 ]; do
nts=$(cat /sys/kernel/debug/hsr/hsr*/node_table)
# We need entries in the node tables, and they need to be merged
if (echo "$nts" | grep -qE "^([0-9a-f]{2}:){5}") && \
! (echo "$nts" | grep -q "00:00:00:00:00:00"); then
return
fi
sleep 1
((WAIT--))
done
check_err 1 "Failed to wait for merged node table entries"
}
setup_topo()
{
local proto="$1"
if [ "$proto" = "HSRv0" ]; then
setup_hsr_topo 0
wait_for_hsr_node_table
elif [ "$proto" = "HSRv1" ]; then
setup_hsr_topo 1
wait_for_hsr_node_table
elif [ "$proto" = "PRP" ]; then
setup_prp_topo
else
check_err 1 "Unknown protocol (${proto})"
fi
}
check_ping()
{
local node="$1"
local dst="$2"
local accepted_dups="$3"
local ping_args="-q -i 0.01 -c 400"
log_info "Running ping $node -> $dst"
# shellcheck disable=SC2086
output=$(ip netns exec "$node" ping $ping_args "$dst" | \
grep "packets transmitted")
log_info "$output"
dups=0
loss=0
if [[ "$output" =~ \+([0-9]+)" duplicates" ]]; then
dups="${BASH_REMATCH[1]}"
fi
if [[ "$output" =~ ([0-9\.]+\%)" packet loss" ]]; then
loss="${BASH_REMATCH[1]}"
fi
if [ "$dups" -gt "$accepted_dups" ]; then
check_err 1 "Unexpected duplicate packets (${dups})"
fi
if [ "$loss" != "0%" ]; then
check_err 1 "Unexpected packet loss (${loss})"
fi
}
test_clean()
{
local proto="$1"
RET=0
tname="${FUNCNAME[0]} - ${proto}"
setup_topo "$proto"
if ((RET != ksft_pass)); then
log_test "${tname} setup"
return
fi
check_ping "$node1" "100.64.0.2" 0
log_test "${tname}"
}
test_clean_hsrv0()
{
test_clean "HSRv0"
}
test_clean_hsrv1()
{
test_clean "HSRv1"
}
test_clean_prp()
{
test_clean "PRP"
}
test_cut_link()
{
local proto="$1"
RET=0
tname="${FUNCNAME[0]} - ${proto}"
setup_topo "$proto"
if ((RET != ksft_pass)); then
log_test "${tname} setup"
return
fi
# Cutting link from subshell, so check_ping can run in the normal shell
# with access to global variables from the test harness.
(
sleep 2
log_info "Cutting link"
ip -net "$node1" link set vethB down
) &
check_ping "$node1" "100.64.0.2" 0
wait
log_test "${tname}"
}
test_cut_link_hsrv0()
{
test_cut_link "HSRv0"
}
test_cut_link_hsrv1()
{
test_cut_link "HSRv1"
}
test_cut_link_prp()
{
test_cut_link "PRP"
}
test_packet_loss()
{
local proto="$1"
local loss="$2"
RET=0
tname="${FUNCNAME[0]} - ${proto}, ${loss}"
setup_topo "$proto"
if ((RET != ksft_pass)); then
log_test "${tname} setup"
return
fi
# Packet loss with lower delay makes sure the packets on the lossy link
# arrive first.
tc -net "$node1" qdisc add dev vethA root netem delay 50ms
tc -net "$node1" qdisc add dev vethB root netem delay 20ms loss "$loss"
check_ping "$node1" "100.64.0.2" 40
log_test "${tname}"
}
test_packet_loss_hsrv0()
{
test_packet_loss "HSRv0" "20%"
}
test_packet_loss_hsrv1()
{
test_packet_loss "HSRv1" "20%"
}
test_packet_loss_prp()
{
test_packet_loss "PRP" "20%"
}
test_high_packet_loss_hsrv0()
{
test_packet_loss "HSRv0" "80%"
}
test_high_packet_loss_hsrv1()
{
test_packet_loss "HSRv1" "80%"
}
test_high_packet_loss_prp()
{
test_packet_loss "PRP" "80%"
}
test_reordering()
{
local proto="$1"
RET=0
tname="${FUNCNAME[0]} - ${proto}"
setup_topo "$proto"
if ((RET != ksft_pass)); then
log_test "${tname} setup"
return
fi
tc -net "$node1" qdisc add dev vethA root netem delay 50ms
tc -net "$node1" qdisc add dev vethB root netem delay 50ms reorder 20%
check_ping "$node1" "100.64.0.2" 40
log_test "${tname}"
}
test_reordering_hsrv0()
{
test_reordering "HSRv0"
}
test_reordering_hsrv1()
{
test_reordering "HSRv1"
}
test_reordering_prp()
{
test_reordering "PRP"
}
cleanup()
{
cleanup_all_ns
}
trap cleanup EXIT
tests_run
exit $EXIT_STATUS