1#!/bin/bash 2# SPDX-License-Identifier: GPL-2.0 3# shellcheck disable=SC2329 4 5source ../lib.sh 6 7ALL_TESTS=" 8 test_clean_hsrv0 9 test_cut_link_hsrv0 10 test_clean_hsrv1 11 test_cut_link_hsrv1 12 test_clean_prp 13 test_cut_link_prp 14 test_packet_loss_prp 15 test_high_packet_loss_prp 16 test_reordering_prp 17" 18 19# The tests are running ping for 5sec with a relatively short interval in 20# different scenarios with faulty links (cut links, packet loss, delay, 21# reordering) that should be recoverable by HSR/PRP. The ping interval (10ms) 22# is short enough that the base delay (50ms) leads to a queue in the netem 23# qdiscs which is needed for reordering. 24 25setup_hsr_topo() 26{ 27 # Three HSR nodes in a ring, every node has a LAN A interface connected 28 # to the LAN B interface of the next node. 29 # 30 # node1 node2 31 # 32 # vethA -------- vethB 33 # hsr1 hsr2 34 # vethB vethA 35 # \ / 36 # vethA vethB 37 # hsr3 38 # 39 # node3 40 41 local ver="$1" 42 43 setup_ns node1 node2 node3 44 45 # veth links 46 # shellcheck disable=SC2154 # variables assigned by setup_ns 47 ip link add vethA netns "$node1" type veth peer name vethB netns "$node2" 48 # shellcheck disable=SC2154 # variables assigned by setup_ns 49 ip link add vethA netns "$node2" type veth peer name vethB netns "$node3" 50 ip link add vethA netns "$node3" type veth peer name vethB netns "$node1" 51 52 # MAC addresses (not needed for HSR operation, but helps with debugging) 53 ip -net "$node1" link set address 00:11:22:00:01:01 dev vethA 54 ip -net "$node1" link set address 00:11:22:00:01:02 dev vethB 55 56 ip -net "$node2" link set address 00:11:22:00:02:01 dev vethA 57 ip -net "$node2" link set address 00:11:22:00:02:02 dev vethB 58 59 ip -net "$node3" link set address 00:11:22:00:03:01 dev vethA 60 ip -net "$node3" link set address 00:11:22:00:03:02 dev vethB 61 62 # HSR interfaces 63 ip -net "$node1" link add name hsr1 type hsr proto 0 version "$ver" \ 64 slave1 vethA slave2 vethB supervision 45 65 ip -net "$node2" link add name hsr2 type hsr proto 0 version "$ver" \ 66 slave1 vethA slave2 vethB supervision 45 67 ip -net "$node3" link add name hsr3 type hsr proto 0 version "$ver" \ 68 slave1 vethA slave2 vethB supervision 45 69 70 # IP addresses 71 ip -net "$node1" addr add 100.64.0.1/24 dev hsr1 72 ip -net "$node2" addr add 100.64.0.2/24 dev hsr2 73 ip -net "$node3" addr add 100.64.0.3/24 dev hsr3 74 75 # Set all links up 76 ip -net "$node1" link set vethA up 77 ip -net "$node1" link set vethB up 78 ip -net "$node1" link set hsr1 up 79 80 ip -net "$node2" link set vethA up 81 ip -net "$node2" link set vethB up 82 ip -net "$node2" link set hsr2 up 83 84 ip -net "$node3" link set vethA up 85 ip -net "$node3" link set vethB up 86 ip -net "$node3" link set hsr3 up 87} 88 89setup_prp_topo() 90{ 91 # Two PRP nodes, connected by two links (treated as LAN A and LAN B). 92 # 93 # vethA ----- vethA 94 # prp1 prp2 95 # vethB ----- vethB 96 # 97 # node1 node2 98 99 setup_ns node1 node2 100 101 # veth links 102 ip link add vethA netns "$node1" type veth peer name vethA netns "$node2" 103 ip link add vethB netns "$node1" type veth peer name vethB netns "$node2" 104 105 # MAC addresses will be copied from LAN A interface 106 ip -net "$node1" link set address 00:11:22:00:00:01 dev vethA 107 ip -net "$node2" link set address 00:11:22:00:00:02 dev vethA 108 109 # PRP interfaces 110 ip -net "$node1" link add name prp1 type hsr \ 111 slave1 vethA slave2 vethB supervision 45 proto 1 112 ip -net "$node2" link add name prp2 type hsr \ 113 slave1 vethA slave2 vethB supervision 45 proto 1 114 115 # IP addresses 116 ip -net "$node1" addr add 100.64.0.1/24 dev prp1 117 ip -net "$node2" addr add 100.64.0.2/24 dev prp2 118 119 # All links up 120 ip -net "$node1" link set vethA up 121 ip -net "$node1" link set vethB up 122 ip -net "$node1" link set prp1 up 123 124 ip -net "$node2" link set vethA up 125 ip -net "$node2" link set vethB up 126 ip -net "$node2" link set prp2 up 127} 128 129wait_for_hsr_node_table() 130{ 131 log_info "Wait for node table entries to be merged." 132 WAIT=5 133 while [ "${WAIT}" -gt 0 ]; do 134 nts=$(cat /sys/kernel/debug/hsr/hsr*/node_table) 135 136 # We need entries in the node tables, and they need to be merged 137 if (echo "$nts" | grep -qE "^([0-9a-f]{2}:){5}") && \ 138 ! (echo "$nts" | grep -q "00:00:00:00:00:00"); then 139 return 140 fi 141 142 sleep 1 143 ((WAIT--)) 144 done 145 check_err 1 "Failed to wait for merged node table entries" 146} 147 148setup_topo() 149{ 150 local proto="$1" 151 152 if [ "$proto" = "HSRv0" ]; then 153 setup_hsr_topo 0 154 wait_for_hsr_node_table 155 elif [ "$proto" = "HSRv1" ]; then 156 setup_hsr_topo 1 157 wait_for_hsr_node_table 158 elif [ "$proto" = "PRP" ]; then 159 setup_prp_topo 160 else 161 check_err 1 "Unknown protocol (${proto})" 162 fi 163} 164 165check_ping() 166{ 167 local node="$1" 168 local dst="$2" 169 local accepted_dups="$3" 170 local ping_args="-q -i 0.01 -c 400" 171 172 log_info "Running ping $node -> $dst" 173 # shellcheck disable=SC2086 174 output=$(ip netns exec "$node" ping $ping_args "$dst" | \ 175 grep "packets transmitted") 176 log_info "$output" 177 178 dups=0 179 loss=0 180 181 if [[ "$output" =~ \+([0-9]+)" duplicates" ]]; then 182 dups="${BASH_REMATCH[1]}" 183 fi 184 if [[ "$output" =~ ([0-9\.]+\%)" packet loss" ]]; then 185 loss="${BASH_REMATCH[1]}" 186 fi 187 188 if [ "$dups" -gt "$accepted_dups" ]; then 189 check_err 1 "Unexpected duplicate packets (${dups})" 190 fi 191 if [ "$loss" != "0%" ]; then 192 check_err 1 "Unexpected packet loss (${loss})" 193 fi 194} 195 196test_clean() 197{ 198 local proto="$1" 199 200 RET=0 201 tname="${FUNCNAME[0]} - ${proto}" 202 203 setup_topo "$proto" 204 if ((RET != ksft_pass)); then 205 log_test "${tname} setup" 206 return 207 fi 208 209 check_ping "$node1" "100.64.0.2" 0 210 211 log_test "${tname}" 212} 213 214test_clean_hsrv0() 215{ 216 test_clean "HSRv0" 217} 218 219test_clean_hsrv1() 220{ 221 test_clean "HSRv1" 222} 223 224test_clean_prp() 225{ 226 test_clean "PRP" 227} 228 229test_cut_link() 230{ 231 local proto="$1" 232 233 RET=0 234 tname="${FUNCNAME[0]} - ${proto}" 235 236 setup_topo "$proto" 237 if ((RET != ksft_pass)); then 238 log_test "${tname} setup" 239 return 240 fi 241 242 # Cutting link from subshell, so check_ping can run in the normal shell 243 # with access to global variables from the test harness. 244 ( 245 sleep 2 246 log_info "Cutting link" 247 ip -net "$node1" link set vethB down 248 ) & 249 check_ping "$node1" "100.64.0.2" 0 250 251 wait 252 log_test "${tname}" 253} 254 255 256test_cut_link_hsrv0() 257{ 258 test_cut_link "HSRv0" 259} 260 261test_cut_link_hsrv1() 262{ 263 test_cut_link "HSRv1" 264} 265 266test_cut_link_prp() 267{ 268 test_cut_link "PRP" 269} 270 271test_packet_loss() 272{ 273 local proto="$1" 274 local loss="$2" 275 276 RET=0 277 tname="${FUNCNAME[0]} - ${proto}, ${loss}" 278 279 setup_topo "$proto" 280 if ((RET != ksft_pass)); then 281 log_test "${tname} setup" 282 return 283 fi 284 285 # Packet loss with lower delay makes sure the packets on the lossy link 286 # arrive first. 287 tc -net "$node1" qdisc add dev vethA root netem delay 50ms 288 tc -net "$node1" qdisc add dev vethB root netem delay 20ms loss "$loss" 289 290 check_ping "$node1" "100.64.0.2" 40 291 292 log_test "${tname}" 293} 294 295test_packet_loss_prp() 296{ 297 test_packet_loss "PRP" "20%" 298} 299 300test_high_packet_loss_prp() 301{ 302 test_packet_loss "PRP" "80%" 303} 304 305test_reordering() 306{ 307 local proto="$1" 308 309 RET=0 310 tname="${FUNCNAME[0]} - ${proto}" 311 312 setup_topo "$proto" 313 if ((RET != ksft_pass)); then 314 log_test "${tname} setup" 315 return 316 fi 317 318 tc -net "$node1" qdisc add dev vethA root netem delay 50ms 319 tc -net "$node1" qdisc add dev vethB root netem delay 50ms reorder 20% 320 321 check_ping "$node1" "100.64.0.2" 40 322 323 log_test "${tname}" 324} 325 326test_reordering_prp() 327{ 328 test_reordering "PRP" 329} 330 331cleanup() 332{ 333 cleanup_all_ns 334} 335 336trap cleanup EXIT 337 338tests_run 339 340exit $EXIT_STATUS 341