Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/bash -e
2# SPDX-License-Identifier: GPL-2.0
3#
4# xfrm/IPsec tests.
5# Currently implemented:
6# - ICMP error source address verification (IETF RFC 4301 section 6)
7# - ICMP MTU exceeded handling over IPsec tunnels.
8#
9# Addresses and topology:
10# IPv4 prefix 10.1.c.d IPv6 prefix fc00:c::d/64 where c is the segment number
11# and d is the interface identifier.
12# IPv6 uses the same c:d as IPv4, and start with IPv6 prefix instead ipv4 prefix
13#
14# Network topology default: ns_set_v4 or ns_set_v6
15# 1.1 1.2 2.1 2.2 3.1 3.2 4.1 4.2 5.1 5.2 6.1 6.2
16# eth0 eth1 eth0 eth1 eth0 eth1 eth0 eth1 eth0 eth1 eth0 eth1
17# a -------- r1 -------- s1 -------- r2 -------- s2 -------- r3 -------- b
18# a, b = Alice and Bob hosts without IPsec.
19# r1, r2, r3 routers, without IPsec
20# s1, s2, IPsec gateways/routers that setup tunnel(s).
21
22# Network topology x: IPsec gateway that generates ICMP response - ns_set_v4x or ns_set_v6x
23# 1.1 1.2 2.1 2.2 3.1 3.2 4.1 4.2 5.1 5.2
24# eth0 eth1 eth0 eth1 eth0 eth1 eth0 eth1 eth0 eth1
25# a -------- r1 -------- s1 -------- r2 -------- s2 -------- b
26
27. lib.sh
28
29EXIT_ON_TEST_FAIL=no
30PAUSE=no
31VERBOSE=${VERBOSE:-0}
32DEBUG=0
33
34# Name Description
35tests="
36 unreachable_ipv4 IPv4 unreachable from router r3
37 unreachable_ipv6 IPv6 unreachable from router r3
38 unreachable_gw_ipv4 IPv4 unreachable from IPsec gateway s2
39 unreachable_gw_ipv6 IPv6 unreachable from IPsec gateway s2
40 mtu_ipv4_s2 IPv4 MTU exceeded from IPsec gateway s2
41 mtu_ipv6_s2 IPv6 MTU exceeded from IPsec gateway s2
42 mtu_ipv4_r2 IPv4 MTU exceeded from ESP router r2
43 mtu_ipv6_r2 IPv6 MTU exceeded from ESP router r2
44 mtu_ipv4_r3 IPv4 MTU exceeded from router r3
45 mtu_ipv6_r3 IPv6 MTU exceeded from router r3"
46
47prefix4="10.1"
48prefix6="fc00"
49
50run_cmd_err() {
51 cmd="$*"
52
53 if [ "$VERBOSE" -gt 0 ]; then
54 printf " COMMAND: %s\n" "$cmd"
55 fi
56
57 out="$($cmd 2>&1)" && rc=0 || rc=$?
58 if [ "$VERBOSE" -gt 1 ] && [ -n "$out" ]; then
59 echo " $out"
60 echo
61 fi
62 return 0
63}
64
65run_cmd() {
66 run_cmd_err "$@" || exit 1
67}
68
69run_test() {
70 # If errexit is set, unset it for sub-shell and restore after test
71 errexit=0
72 if [[ $- =~ "e" ]]; then
73 errexit=1
74 set +e
75 fi
76
77 (
78 unset IFS
79
80 # shellcheck disable=SC2030 # fail is read by trap/cleanup within this subshell
81 fail="yes"
82
83 # Since cleanup() relies on variables modified by this sub shell,
84 # it has to run in this context.
85 trap 'log_test_error $?; cleanup' EXIT INT TERM
86
87 if [ "$VERBOSE" -gt 0 ]; then
88 printf "\n#############################################################\n\n"
89 fi
90
91 ret=0
92 case "${name}" in
93 # can't use eval and test names shell check will complain about unused code
94 unreachable_ipv4) test_unreachable_ipv4 ;;
95 unreachable_ipv6) test_unreachable_ipv6 ;;
96 unreachable_gw_ipv4) test_unreachable_gw_ipv4 ;;
97 unreachable_gw_ipv6) test_unreachable_gw_ipv6 ;;
98 mtu_ipv4_s2) test_mtu_ipv4_s2 ;;
99 mtu_ipv6_s2) test_mtu_ipv6_s2 ;;
100 mtu_ipv4_r2) test_mtu_ipv4_r2 ;;
101 mtu_ipv6_r2) test_mtu_ipv6_r2 ;;
102 mtu_ipv4_r3) test_mtu_ipv4_r3 ;;
103 mtu_ipv6_r3) test_mtu_ipv6_r3 ;;
104 esac
105 ret=$?
106
107 if [ $ret -eq 0 ]; then
108 fail="no"
109
110 if [ "$VERBOSE" -gt 1 ]; then
111 show_icmp_filter
112 fi
113
114 printf "TEST: %-60s [ PASS ]\n" "${desc}"
115 elif [ $ret -eq "$ksft_skip" ]; then
116 fail="no"
117 printf "TEST: %-60s [SKIP]\n" "${desc}"
118 fi
119
120 return $ret
121 )
122 ret=$?
123
124 [ $errexit -eq 1 ] && set -e
125
126 case $ret in
127 0)
128 all_skipped=false
129 [ "$exitcode" -eq "$ksft_skip" ] && exitcode=0
130 ;;
131 "$ksft_skip")
132 [ $all_skipped = true ] && exitcode=$ksft_skip
133 ;;
134 *)
135 all_skipped=false
136 exitcode=1
137 ;;
138 esac
139
140 return 0 # don't trigger errexit (-e); actual status in exitcode
141}
142
143setup_namespaces() {
144 local namespaces=""
145
146 NS_A=""
147 NS_B=""
148 NS_R1=""
149 NS_R2=""
150 NS_R3=""
151 NS_S1=""
152 NS_S2=""
153
154 for ns in ${ns_set}; do
155 namespaces="$namespaces NS_${ns^^}"
156 done
157
158 # shellcheck disable=SC2086 # setup_ns expects unquoted list
159 setup_ns $namespaces
160
161 ns_active= #ordered list of namespaces for this test.
162
163 [ -n "${NS_A}" ] && ns_a=(ip netns exec "${NS_A}") && ns_active="${ns_active} $NS_A"
164 [ -n "${NS_R1}" ] && ns_active="${ns_active} $NS_R1"
165 [ -n "${NS_S1}" ] && ns_s1=(ip netns exec "${NS_S1}") && ns_active="${ns_active} $NS_S1"
166 [ -n "${NS_R2}" ] && ns_r2=(ip netns exec "${NS_R2}") && ns_active="${ns_active} $NS_R2"
167 [ -n "${NS_S2}" ] && ns_s2=(ip netns exec "${NS_S2}") && ns_active="${ns_active} $NS_S2"
168 [ -n "${NS_R3}" ] && ns_r3=(ip netns exec "${NS_R3}") && ns_active="${ns_active} $NS_R3"
169 [ -n "${NS_B}" ] && ns_active="${ns_active} $NS_B"
170}
171
172addr_add() {
173 local -a ns_cmd=(ip netns exec "$1")
174 local addr="$2"
175 local dev="$3"
176
177 run_cmd "${ns_cmd[@]}" ip addr add "${addr}" dev "${dev}"
178 run_cmd "${ns_cmd[@]}" ip link set up "${dev}"
179}
180
181veth_add() {
182 local ns=$2
183 local pns=$1
184 local -a ns_cmd=(ip netns exec "${pns}")
185 local ln="eth0"
186 local rn="eth1"
187
188 run_cmd "${ns_cmd[@]}" ip link add "${ln}" type veth peer name "${rn}" netns "${ns}"
189}
190
191show_icmp_filter() {
192 run_cmd "${ns_r2[@]}" nft list ruleset
193 echo "$out"
194}
195
196setup_icmp_filter() {
197 run_cmd "${ns_r2[@]}" nft add table inet filter
198 run_cmd "${ns_r2[@]}" nft add chain inet filter FORWARD \
199 '{ type filter hook forward priority filter; policy drop ; }'
200 run_cmd "${ns_r2[@]}" nft add rule inet filter FORWARD counter ip protocol esp \
201 counter log accept
202 run_cmd "${ns_r2[@]}" nft add rule inet filter FORWARD counter ip protocol \
203 icmp counter log drop
204
205 if [ "$VERBOSE" -gt 0 ]; then
206 run_cmd "${ns_r2[@]}" nft list ruleset
207 echo "$out"
208 fi
209}
210
211setup_icmpv6_filter() {
212 run_cmd "${ns_r2[@]}" nft add table inet filter
213 run_cmd "${ns_r2[@]}" nft add chain inet filter FORWARD \
214 '{ type filter hook forward priority filter; policy drop ; }'
215 run_cmd "${ns_r2[@]}" nft add rule inet filter FORWARD ip6 nexthdr \
216 ipv6-icmp icmpv6 type echo-request counter log drop
217 run_cmd "${ns_r2[@]}" nft add rule inet filter FORWARD ip6 nexthdr esp \
218 counter log accept
219 run_cmd "${ns_r2[@]}" nft add rule inet filter FORWARD ip6 nexthdr \
220 ipv6-icmp icmpv6 type \
221 '{nd-neighbor-solicit,nd-neighbor-advert,nd-router-solicit,nd-router-advert}' \
222 counter log drop
223 if [ "$VERBOSE" -gt 0 ]; then
224 run_cmd "${ns_r2[@]}" nft list ruleset
225 echo "$out"
226 fi
227}
228
229set_xfrm_params() {
230 s1_src=${src}
231 s1_dst=${dst}
232 s1_src_net=${src_net}
233 s1_dst_net=${dst_net}
234}
235
236setup_ns_set_v4() {
237 ns_set="a r1 s1 r2 s2 r3 b" # Network topology default
238 imax=$(echo "$ns_set" | wc -w) # number of namespaces in this topology
239
240 src="10.1.3.1"
241 dst="10.1.4.2"
242 src_net="10.1.1.0/24"
243 dst_net="10.1.6.0/24"
244
245 prefix=${prefix4}
246 prefix_len=24
247 s="."
248 S="."
249
250 set_xfrm_params
251}
252
253setup_ns_set_v4x() {
254 ns_set="a r1 s1 r2 s2 b" # Network topology: x
255 imax=$(echo "$ns_set" | wc -w) # number of namespaces in this topology
256 prefix=${prefix4}
257 s="."
258 S="."
259 src="10.1.3.1"
260 dst="10.1.4.2"
261 src_net="10.1.1.0/24"
262 dst_net="10.1.5.0/24"
263 prefix_len=24
264
265 set_xfrm_params
266}
267
268setup_ns_set_v6() {
269 ns_set="a r1 s1 r2 s2 r3 b" # Network topology default
270 imax=$(echo "$ns_set" | wc -w) # number of namespaces in this topology
271 prefix=${prefix6}
272 s=":"
273 S="::"
274 src="fc00:3::1"
275 dst="fc00:4::2"
276 src_net="fc00:1::0/64"
277 dst_net="fc00:6::0/64"
278 prefix_len=64
279
280 set_xfrm_params
281}
282
283setup_ns_set_v6x() {
284 ns_set="a r1 s1 r2 s2 b" # Network topology: x
285 imax=$(echo "$ns_set" | wc -w)
286 prefix=${prefix6}
287 s=":"
288 S="::"
289 src="fc00:3::1"
290 dst="fc00:4::2"
291 src_net="fc00:1::0/64"
292 dst_net="fc00:5::0/64"
293 prefix_len=64
294
295 set_xfrm_params
296}
297
298setup_network() {
299 # Create veths and add addresses
300 local -a ns_cmd
301 i=1
302 p=""
303 for ns in ${ns_active}; do
304 ns_cmd=(ip netns exec "${ns}")
305
306 if [ "${i}" -ne 1 ]; then
307 # Create veth between previous and current namespace
308 veth_add "${p}" "${ns}"
309 # Add addresses: previous gets .1 on eth0, current gets .2 on eth1
310 addr_add "${p}" "${prefix}${s}$((i-1))${S}1/${prefix_len}" eth0
311 addr_add "${ns}" "${prefix}${s}$((i-1))${S}2/${prefix_len}" eth1
312 fi
313
314 # Enable forwarding
315 run_cmd "${ns_cmd[@]}" sysctl -q net/ipv4/ip_forward=1
316 run_cmd "${ns_cmd[@]}" sysctl -q net/ipv6/conf/all/forwarding=1
317 run_cmd "${ns_cmd[@]}" sysctl -q net/ipv6/conf/default/accept_dad=0
318
319 p=${ns}
320 i=$((i + 1))
321 done
322
323 # Add routes (needs all addresses to exist first)
324 i=1
325 for ns in ${ns_active}; do
326 ns_cmd=(ip netns exec "${ns}")
327
328 # Forward routes to networks beyond this node
329 if [ "${i}" -ne "${imax}" ]; then
330 nhf="${prefix}${s}${i}${S}2" # nexthop forward
331 for j in $(seq $((i + 1)) "${imax}"); do
332 run_cmd "${ns_cmd[@]}" ip route replace \
333 "${prefix}${s}${j}${S}0/${prefix_len}" via "${nhf}"
334 done
335 fi
336
337 # Reverse routes to networks before this node
338 if [ "${i}" -gt 1 ]; then
339 nhr="${prefix}${s}$((i-1))${S}1" # nexthop reverse
340 for j in $(seq 1 $((i - 2))); do
341 run_cmd "${ns_cmd[@]}" ip route replace \
342 "${prefix}${s}${j}${S}0/${prefix_len}" via "${nhr}"
343 done
344 fi
345
346 i=$((i + 1))
347 done
348}
349
350setup_xfrm_mode() {
351 local MODE=${1:-tunnel}
352 if [ "${MODE}" != "tunnel" ] && [ "${MODE}" != "beet" ]; then
353 echo "xfrm mode ${MODE} not supported"
354 log_test_error
355 return 1
356 fi
357
358 run_cmd "${ns_s1[@]}" ip xfrm policy add src "${s1_src_net}" dst "${s1_dst_net}" dir out \
359 tmpl src "${s1_src}" dst "${s1_dst}" proto esp reqid 1 mode "${MODE}"
360
361 # no "input" policies. we are only doing forwarding so far
362
363 run_cmd "${ns_s1[@]}" ip xfrm policy add src "${s1_dst_net}" dst "${s1_src_net}" dir fwd \
364 flag icmp tmpl src "${s1_dst}" dst "${s1_src}" proto esp reqid 2 mode "${MODE}"
365
366 run_cmd "${ns_s1[@]}" ip xfrm state add src "${s1_src}" dst "${s1_dst}" proto esp spi 1 \
367 reqid 1 mode "${MODE}" aead 'rfc4106(gcm(aes))' \
368 0x1111111111111111111111111111111111111111 96 \
369 sel src "${s1_src_net}" dst "${s1_dst_net}" dir out
370
371 run_cmd "${ns_s1[@]}" ip xfrm state add src "${s1_dst}" dst "${s1_src}" proto esp spi 2 \
372 reqid 2 flag icmp replay-window 8 mode "${MODE}" aead 'rfc4106(gcm(aes))' \
373 0x2222222222222222222222222222222222222222 96 \
374 sel src "${s1_dst_net}" dst "${s1_src_net}" dir in
375
376 run_cmd "${ns_s2[@]}" ip xfrm policy add src "${s1_dst_net}" dst "${s1_src_net}" dir out \
377 flag icmp tmpl src "${s1_dst}" dst "${s1_src}" proto esp reqid 2 mode "${MODE}"
378
379 run_cmd "${ns_s2[@]}" ip xfrm policy add src "${s1_src_net}" dst "${s1_dst_net}" dir fwd \
380 tmpl src "${s1_src}" dst "${s1_dst}" proto esp reqid 1 mode "${MODE}"
381
382 run_cmd "${ns_s2[@]}" ip xfrm state add src "${s1_dst}" dst "${s1_src}" proto esp spi 2 \
383 reqid 2 mode "${MODE}" aead 'rfc4106(gcm(aes))' \
384 0x2222222222222222222222222222222222222222 96 \
385 sel src "${s1_dst_net}" dst "${s1_src_net}" dir out
386
387 run_cmd "${ns_s2[@]}" ip xfrm state add src "${s1_src}" dst "${s1_dst}" proto esp spi 1 \
388 reqid 1 flag icmp replay-window 8 mode "${MODE}" aead 'rfc4106(gcm(aes))' \
389 0x1111111111111111111111111111111111111111 96 \
390 sel src "${s1_src_net}" dst "${s1_dst_net}" dir in
391}
392
393setup_xfrm() {
394 setup_xfrm_mode tunnel
395}
396
397setup() {
398 [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return "$ksft_skip"
399
400 for arg; do
401 case "${arg}" in
402 ns_set_v4) setup_ns_set_v4 ;;
403 ns_set_v4x) setup_ns_set_v4x ;;
404 ns_set_v6) setup_ns_set_v6 ;;
405 ns_set_v6x) setup_ns_set_v6x ;;
406 namespaces) setup_namespaces ;;
407 network) setup_network ;;
408 xfrm) setup_xfrm ;;
409 icmp_filter) setup_icmp_filter ;;
410 icmpv6_filter) setup_icmpv6_filter ;;
411 *) echo " ${arg} not supported"; return 1 ;;
412 esac || return 1
413 done
414}
415
416# shellcheck disable=SC2317 # called via trap
417pause() {
418 echo
419 echo "Pausing. Hit enter to continue"
420 read -r _
421}
422
423# shellcheck disable=SC2317 # called via trap
424log_test_error() {
425 # shellcheck disable=SC2031 # fail is set in subshell, read via trap
426 if [ "${fail}" = "yes" ] && [ -n "${desc}" ]; then
427 if [ "$VERBOSE" -gt 0 ]; then
428 show_icmp_filter
429 fi
430 printf "TEST: %-60s [ FAIL ] %s\n" "${desc}" "${name}"
431 [ -n "${cmd}" ] && printf '%s\n\n' "${cmd}"
432 [ -n "${out}" ] && printf '%s\n\n' "${out}"
433 fi
434}
435
436# shellcheck disable=SC2317 # called via trap
437cleanup() {
438 # shellcheck disable=SC2031 # fail is set in subshell, read via trap
439 [[ "$PAUSE" = "always" || ( "$PAUSE" = "fail" && "$fail" = "yes" ) ]] && pause
440 cleanup_all_ns
441 # shellcheck disable=SC2031 # fail is set in subshell, read via trap
442 [ "${EXIT_ON_TEST_FAIL}" = "yes" ] && [ "${fail}" = "yes" ] && exit 1
443}
444
445test_unreachable_ipv6() {
446 setup ns_set_v6 namespaces network xfrm icmpv6_filter || return "$ksft_skip"
447 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:6::2
448 run_cmd_err "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:6::3
449 rc=0
450 echo -e "$out" | grep -q -E 'From fc00:5::2 icmp_seq.* Destination' || rc=1
451 return "${rc}"
452}
453
454test_unreachable_gw_ipv6() {
455 setup ns_set_v6x namespaces network xfrm icmpv6_filter || return "$ksft_skip"
456 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:5::2
457 run_cmd_err "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:5::3
458 rc=0
459 echo -e "$out" | grep -q -E 'From fc00:4::2 icmp_seq.* Destination' || rc=1
460 return "${rc}"
461}
462
463test_unreachable_ipv4() {
464 setup ns_set_v4 namespaces network icmp_filter xfrm || return "$ksft_skip"
465 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.6.2
466 run_cmd_err "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.6.3
467 rc=0
468 echo -e "$out" | grep -q -E 'From 10.1.5.2 icmp_seq.* Destination' || rc=1
469 return "${rc}"
470}
471
472test_unreachable_gw_ipv4() {
473 setup ns_set_v4x namespaces network icmp_filter xfrm || return "$ksft_skip"
474 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.5.2
475 run_cmd_err "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.5.3
476 rc=0
477 echo -e "$out" | grep -q -E 'From 10.1.4.2 icmp_seq.* Destination' || rc=1
478 return "${rc}"
479}
480
481test_mtu_ipv4_r2() {
482 setup ns_set_v4 namespaces network icmp_filter xfrm || return "$ksft_skip"
483 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.6.2
484 run_cmd "${ns_r2[@]}" ip route replace 10.1.3.0/24 dev eth1 src 10.1.3.2 mtu 1300
485 run_cmd "${ns_r2[@]}" ip route replace 10.1.4.0/24 dev eth0 src 10.1.4.1 mtu 1300
486 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
487 run_cmd "${ns_a[@]}" ping -M do -s 1300 -W 5 -w 4 -c 1 10.1.6.2 || true
488 rc=0
489 echo -e "$out" | grep -q -E "From 10.1.2.2 icmp_seq=.* Frag needed and DF set" || rc=1
490 return "${rc}"
491}
492
493test_mtu_ipv6_r2() {
494 setup ns_set_v6 namespaces network xfrm icmpv6_filter || return "$ksft_skip"
495 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:6::2
496 run_cmd "${ns_r2[@]}" ip -6 route replace fc00:3::/64 \
497 dev eth1 metric 256 src fc00:3::2 mtu 1300
498 run_cmd "${ns_r2[@]}" ip -6 route replace fc00:4::/64 \
499 dev eth0 metric 256 src fc00:4::1 mtu 1300
500 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
501 run_cmd "${ns_a[@]}" ping -M do -s 1300 -W 5 -w 4 -c 1 fc00:6::2 || true
502 rc=0
503 echo -e "$out" | grep -q -E "From fc00:2::2 icmp_seq=.* Packet too big: mtu=1230" || rc=1
504 return "${rc}"
505}
506
507test_mtu_ipv4_r3() {
508 setup ns_set_v4 namespaces network icmp_filter xfrm || return "$ksft_skip"
509 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.6.2
510 run_cmd "${ns_r3[@]}" ip route replace 10.1.6.0/24 dev eth0 mtu 1300
511 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
512 run_cmd "${ns_a[@]}" ping -M do -s 1350 -W 5 -w 4 -c 1 10.1.6.2 || true
513 rc=0
514 echo -e "$out" | grep -q -E "From 10.1.5.2 .* Frag needed and DF set \(mtu = 1300\)" || rc=1
515 return "${rc}"
516}
517
518test_mtu_ipv4_s2() {
519 setup ns_set_v4x namespaces network icmp_filter xfrm || return "$ksft_skip"
520 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 10.1.5.2
521 run_cmd "${ns_s2[@]}" ip route replace 10.1.5.0/24 dev eth0 src 10.1.5.1 mtu 1300
522 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
523 run_cmd "${ns_a[@]}" ping -M do -s 1350 -W 5 -w 4 -c 1 10.1.5.2 || true
524 rc=0
525 echo -e "$out" | grep -q -E "From 10.1.4.2.*Frag needed and DF set \(mtu = 1300\)" || rc=1
526 return "${rc}"
527}
528
529test_mtu_ipv6_s2() {
530 setup ns_set_v6x namespaces network xfrm icmpv6_filter || return "$ksft_skip"
531 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:5::2
532 run_cmd "${ns_s2[@]}" ip -6 route replace fc00:5::/64 dev eth0 metric 256 mtu 1300
533 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
534 run_cmd "${ns_a[@]}" ping -M do -s 1350 -W 5 -w 4 -c 1 fc00:5::2 || true
535 rc=0
536 echo -e "$out" | grep -q -E "From fc00:4::2.*Packet too big: mtu=1300" || rc=1
537 return "${rc}"
538}
539
540test_mtu_ipv6_r3() {
541 setup ns_set_v6 namespaces network xfrm icmpv6_filter || return "$ksft_skip"
542 run_cmd "${ns_a[@]}" ping -W 5 -w 4 -c 1 fc00:6::2
543 run_cmd "${ns_r3[@]}" ip -6 route replace fc00:6::/64 dev eth1 metric 256 mtu 1300
544 # shellcheck disable=SC1010 # -M do: do = dont-fragment, not shell keyword
545 run_cmd "${ns_a[@]}" ping -M do -s 1300 -W 5 -w 4 -c 1 fc00:6::2 || true
546 rc=0
547 echo -e "$out" | grep -q -E "From fc00:5::2 icmp_seq=.* Packet too big: mtu=1300" || rc=1
548 return "${rc}"
549}
550
551################################################################################
552#
553usage() {
554 echo
555 echo "$0 [OPTIONS] [TEST]..."
556 echo "If no TEST argument is given, all tests will be run."
557 echo
558 echo -e "\t-p Pause on fail. Namespaces are kept for diagnostics"
559 echo -e "\t-P Pause after the test. Namespaces are kept for diagnostics"
560 echo -e "\t-v Verbose output. Show commands; -vv Show output and nft rules also"
561 echo "Available tests${tests}"
562 exit 1
563}
564
565################################################################################
566#
567exitcode=0
568all_skipped=true
569out=
570cmd=
571
572while getopts :epPv o; do
573 case $o in
574 e) EXIT_ON_TEST_FAIL=yes ;;
575 P) PAUSE=always ;;
576 p) PAUSE=fail ;;
577 v) VERBOSE=$((VERBOSE + 1)) ;;
578 *) usage ;;
579 esac
580done
581shift $((OPTIND - 1))
582
583IFS=$'\t\n'
584
585for arg; do
586 # Check first that all requested tests are available before running any
587 command -v "test_${arg}" >/dev/null || {
588 echo "=== Test ${arg} not found"
589 usage
590 }
591done
592
593name=""
594desc=""
595fail="no"
596
597for t in ${tests}; do
598 [ "${name}" = "" ] && name="${t}" && continue
599 [ "${desc}" = "" ] && desc="${t}"
600
601 run_this=1
602 for arg; do
603 [ "${arg}" = "${name}" ] && run_this=1 && break
604 run_this=0
605 done
606 if [ $run_this -eq 1 ]; then
607 run_test
608 fi
609 name=""
610 desc=""
611done
612
613exit ${exitcode}