1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# This tests basic flowtable functionality.
5# Creates following default topology:
6#
7# Originator (MTU 9000) <-Router1-> MTU 1500 <-Router2-> Responder (MTU 2000)
8# Router1 is the one doing flow offloading, Router2 has no special
9# purpose other than having a link that is smaller than either Originator
10# and responder, i.e. TCPMSS announced values are too large and will still
11# result in fragmentation and/or PMTU discovery.
12#
13# You can check with different Orgininator/Link/Responder MTU eg:
14# nft_flowtable.sh -o8000 -l1500 -r2000
15#
16
17source lib.sh
18
19ret=0
20SOCAT_TIMEOUT=60
21
22nsin=""
23ns1out=""
24ns2out=""
25
26log_netns=$(sysctl -n net.netfilter.nf_log_all_netns)
27
28checktool "nft --version" "run test without nft tool"
29checktool "socat -h" "run test without socat"
30
31setup_ns ns1 ns2 nsr1 nsr2
32
33cleanup() {
34	ip netns pids "$ns1" | xargs kill 2>/dev/null
35	ip netns pids "$ns2" | xargs kill 2>/dev/null
36
37	cleanup_all_ns
38
39	rm -f "$nsin" "$ns1out" "$ns2out"
40
41	[ "$log_netns" -eq 0 ] && sysctl -q net.netfilter.nf_log_all_netns="$log_netns"
42}
43
44trap cleanup EXIT
45
46sysctl -q net.netfilter.nf_log_all_netns=1
47
48ip link add veth0 netns "$nsr1" type veth peer name eth0 netns "$ns1"
49ip link add veth1 netns "$nsr1" type veth peer name veth0 netns "$nsr2"
50
51ip link add veth1 netns "$nsr2" type veth peer name eth0 netns "$ns2"
52
53for dev in veth0 veth1; do
54    ip -net "$nsr1" link set "$dev" up
55    ip -net "$nsr2" link set "$dev" up
56done
57
58ip -net "$nsr1" addr add 10.0.1.1/24 dev veth0
59ip -net "$nsr1" addr add dead:1::1/64 dev veth0 nodad
60
61ip -net "$nsr2" addr add 10.0.2.1/24 dev veth1
62ip -net "$nsr2" addr add dead:2::1/64 dev veth1 nodad
63
64# set different MTUs so we need to push packets coming from ns1 (large MTU)
65# to ns2 (smaller MTU) to stack either to perform fragmentation (ip_no_pmtu_disc=1),
66# or to do PTMU discovery (send ICMP error back to originator).
67# ns2 is going via nsr2 with a smaller mtu, so that TCPMSS announced by both peers
68# is NOT the lowest link mtu.
69
70omtu=9000
71lmtu=1500
72rmtu=2000
73
74usage(){
75	echo "nft_flowtable.sh [OPTIONS]"
76	echo
77	echo "MTU options"
78	echo "   -o originator"
79	echo "   -l link"
80	echo "   -r responder"
81	exit 1
82}
83
84while getopts "o:l:r:" o
85do
86	case $o in
87		o) omtu=$OPTARG;;
88		l) lmtu=$OPTARG;;
89		r) rmtu=$OPTARG;;
90		*) usage;;
91	esac
92done
93
94if ! ip -net "$nsr1" link set veth0 mtu "$omtu"; then
95	exit 1
96fi
97
98ip -net "$ns1" link set eth0 mtu "$omtu"
99
100if ! ip -net "$nsr2" link set veth1 mtu "$rmtu"; then
101	exit 1
102fi
103
104if ! ip -net "$nsr1" link set veth1 mtu "$lmtu"; then
105	exit 1
106fi
107
108if ! ip -net "$nsr2" link set veth0 mtu "$lmtu"; then
109	exit 1
110fi
111
112ip -net "$ns2" link set eth0 mtu "$rmtu"
113
114# transfer-net between nsr1 and nsr2.
115# these addresses are not used for connections.
116ip -net "$nsr1" addr add 192.168.10.1/24 dev veth1
117ip -net "$nsr1" addr add fee1:2::1/64 dev veth1 nodad
118
119ip -net "$nsr2" addr add 192.168.10.2/24 dev veth0
120ip -net "$nsr2" addr add fee1:2::2/64 dev veth0 nodad
121
122for i in 0 1; do
123  ip netns exec "$nsr1" sysctl net.ipv4.conf.veth$i.forwarding=1 > /dev/null
124  ip netns exec "$nsr2" sysctl net.ipv4.conf.veth$i.forwarding=1 > /dev/null
125done
126
127for ns in "$ns1" "$ns2";do
128  ip -net "$ns" link set eth0 up
129
130  if ! ip netns exec "$ns" sysctl net.ipv4.tcp_no_metrics_save=1 > /dev/null; then
131	echo "ERROR: Check Originator/Responder values (problem during address addition)"
132	exit 1
133  fi
134  # don't set ip DF bit for first two tests
135  ip netns exec "$ns" sysctl net.ipv4.ip_no_pmtu_disc=1 > /dev/null
136done
137
138ip -net "$ns1" addr add 10.0.1.99/24 dev eth0
139ip -net "$ns2" addr add 10.0.2.99/24 dev eth0
140ip -net "$ns1" route add default via 10.0.1.1
141ip -net "$ns2" route add default via 10.0.2.1
142ip -net "$ns1" addr add dead:1::99/64 dev eth0 nodad
143ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad
144ip -net "$ns1" route add default via dead:1::1
145ip -net "$ns2" route add default via dead:2::1
146
147ip -net "$nsr1" route add default via 192.168.10.2
148ip -net "$nsr2" route add default via 192.168.10.1
149
150ip netns exec "$nsr1" nft -f - <<EOF
151table inet filter {
152  flowtable f1 {
153     hook ingress priority 0
154     devices = { veth0, veth1 }
155   }
156
157   counter routed_orig { }
158   counter routed_repl { }
159
160   chain forward {
161      type filter hook forward priority 0; policy drop;
162
163      # flow offloaded? Tag ct with mark 1, so we can detect when it fails.
164      meta oif "veth1" tcp dport 12345 ct mark set 1 flow add @f1 counter name routed_orig accept
165
166      # count packets supposedly offloaded as per direction.
167      ct mark 1 counter name ct direction map { original : routed_orig, reply : routed_repl } accept
168
169      ct state established,related accept
170
171      meta nfproto ipv4 meta l4proto icmp accept
172      meta nfproto ipv6 meta l4proto icmpv6 accept
173   }
174}
175EOF
176
177if [ $? -ne 0 ]; then
178	echo "SKIP: Could not load nft ruleset"
179	exit $ksft_skip
180fi
181
182ip netns exec "$ns2" nft -f - <<EOF
183table inet filter {
184   counter ip4dscp0 { }
185   counter ip4dscp3 { }
186
187   chain input {
188      type filter hook input priority 0; policy accept;
189      meta l4proto tcp goto {
190	      ip dscp cs3 counter name ip4dscp3 accept
191	      ip dscp 0 counter name ip4dscp0 accept
192      }
193   }
194}
195EOF
196
197if [ $? -ne 0 ]; then
198	echo -n "SKIP: Could not load ruleset: "
199	nft --version
200	exit $ksft_skip
201fi
202
203# test basic connectivity
204if ! ip netns exec "$ns1" ping -c 1 -q 10.0.2.99 > /dev/null; then
205  echo "ERROR: $ns1 cannot reach ns2" 1>&2
206  exit 1
207fi
208
209if ! ip netns exec "$ns2" ping -c 1 -q 10.0.1.99 > /dev/null; then
210  echo "ERROR: $ns2 cannot reach $ns1" 1>&2
211  exit 1
212fi
213
214nsin=$(mktemp)
215ns1out=$(mktemp)
216ns2out=$(mktemp)
217
218make_file()
219{
220	name=$1
221
222	SIZE=$((RANDOM % (1024 * 128)))
223	SIZE=$((SIZE + (1024 * 8)))
224	TSIZE=$((SIZE * 1024))
225
226	dd if=/dev/urandom of="$name" bs=1024 count=$SIZE 2> /dev/null
227
228	SIZE=$((RANDOM % 1024))
229	SIZE=$((SIZE + 128))
230	TSIZE=$((TSIZE + SIZE))
231	dd if=/dev/urandom conf=notrunc of="$name" bs=1 count=$SIZE 2> /dev/null
232}
233
234check_counters()
235{
236	local what=$1
237	local ok=1
238
239	local orig repl
240	orig=$(ip netns exec "$nsr1" nft reset counter inet filter routed_orig | grep packets)
241	repl=$(ip netns exec "$nsr1" nft reset counter inet filter routed_repl | grep packets)
242
243	local orig_cnt=${orig#*bytes}
244	local repl_cnt=${repl#*bytes}
245
246	local fs
247	fs=$(du -sb "$nsin")
248	local max_orig=${fs%%/*}
249	local max_repl=$((max_orig/4))
250
251	# flowtable fastpath should bypass normal routing one, i.e. the counters in forward hook
252	# should always be lower than the size of the transmitted file (max_orig).
253	if [ "$orig_cnt" -gt "$max_orig" ];then
254		echo "FAIL: $what: original counter $orig_cnt exceeds expected value $max_orig" 1>&2
255		ret=1
256		ok=0
257	fi
258
259	if [ "$repl_cnt" -gt $max_repl ];then
260		echo "FAIL: $what: reply counter $repl_cnt exceeds expected value $max_repl" 1>&2
261		ret=1
262		ok=0
263	fi
264
265	if [ $ok -eq 1 ]; then
266		echo "PASS: $what"
267	fi
268}
269
270check_dscp()
271{
272	local what=$1
273	local ok=1
274
275	local counter
276	counter=$(ip netns exec "$ns2" nft reset counter inet filter ip4dscp3 | grep packets)
277
278	local pc4=${counter%*bytes*}
279	local pc4=${pc4#*packets}
280
281	counter=$(ip netns exec "$ns2" nft reset counter inet filter ip4dscp0 | grep packets)
282	local pc4z=${counter%*bytes*}
283	local pc4z=${pc4z#*packets}
284
285	case "$what" in
286	"dscp_none")
287		if [ "$pc4" -gt 0 ] || [ "$pc4z" -eq 0 ]; then
288			echo "FAIL: dscp counters do not match, expected dscp3 == 0, dscp0 > 0, but got $pc4,$pc4z" 1>&2
289			ret=1
290			ok=0
291		fi
292		;;
293	"dscp_fwd")
294		if [ "$pc4" -eq 0 ] || [ "$pc4z" -eq 0 ]; then
295			echo "FAIL: dscp counters do not match, expected dscp3 and dscp0 > 0 but got $pc4,$pc4z" 1>&2
296			ret=1
297			ok=0
298		fi
299		;;
300	"dscp_ingress")
301		if [ "$pc4" -eq 0 ] || [ "$pc4z" -gt 0 ]; then
302			echo "FAIL: dscp counters do not match, expected dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2
303			ret=1
304			ok=0
305		fi
306		;;
307	"dscp_egress")
308		if [ "$pc4" -eq 0 ] || [ "$pc4z" -gt 0 ]; then
309			echo "FAIL: dscp counters do not match, expected dscp3 > 0, dscp0 == 0 but got $pc4,$pc4z" 1>&2
310			ret=1
311			ok=0
312		fi
313		;;
314	*)
315		echo "FAIL: Unknown DSCP check" 1>&2
316		ret=1
317		ok=0
318	esac
319
320	if [ "$ok" -eq 1 ] ;then
321		echo "PASS: $what: dscp packet counters match"
322	fi
323}
324
325check_transfer()
326{
327	in=$1
328	out=$2
329	what=$3
330
331	if ! cmp "$in" "$out" > /dev/null 2>&1; then
332		echo "FAIL: file mismatch for $what" 1>&2
333		ls -l "$in"
334		ls -l "$out"
335		return 1
336	fi
337
338	return 0
339}
340
341listener_ready()
342{
343	ss -N "$nsb" -lnt -o "sport = :12345" | grep -q 12345
344}
345
346test_tcp_forwarding_ip()
347{
348	local nsa=$1
349	local nsb=$2
350	local dstip=$3
351	local dstport=$4
352	local lret=0
353
354	timeout "$SOCAT_TIMEOUT" ip netns exec "$nsb" socat -4 TCP-LISTEN:12345,reuseaddr STDIO < "$nsin" > "$ns2out" &
355	lpid=$!
356
357	busywait 1000 listener_ready
358
359	timeout "$SOCAT_TIMEOUT" ip netns exec "$nsa" socat -4 TCP:"$dstip":"$dstport" STDIO < "$nsin" > "$ns1out"
360
361	wait $lpid
362
363	if ! check_transfer "$nsin" "$ns2out" "ns1 -> ns2"; then
364		lret=1
365		ret=1
366	fi
367
368	if ! check_transfer "$nsin" "$ns1out" "ns1 <- ns2"; then
369		lret=1
370		ret=1
371	fi
372
373	return $lret
374}
375
376test_tcp_forwarding()
377{
378	test_tcp_forwarding_ip "$1" "$2" 10.0.2.99 12345
379
380	return $?
381}
382
383test_tcp_forwarding_set_dscp()
384{
385	check_dscp "dscp_none"
386
387ip netns exec "$nsr1" nft -f - <<EOF
388table netdev dscpmangle {
389   chain setdscp0 {
390      type filter hook ingress device "veth0" priority 0; policy accept
391	ip dscp set cs3
392  }
393}
394EOF
395if [ $? -eq 0 ]; then
396	test_tcp_forwarding_ip "$1" "$2"  10.0.2.99 12345
397	check_dscp "dscp_ingress"
398
399	ip netns exec "$nsr1" nft delete table netdev dscpmangle
400else
401	echo "SKIP: Could not load netdev:ingress for veth0"
402fi
403
404ip netns exec "$nsr1" nft -f - <<EOF
405table netdev dscpmangle {
406   chain setdscp0 {
407      type filter hook egress device "veth1" priority 0; policy accept
408      ip dscp set cs3
409  }
410}
411EOF
412if [ $? -eq 0 ]; then
413	test_tcp_forwarding_ip "$1" "$2"  10.0.2.99 12345
414	check_dscp "dscp_egress"
415
416	ip netns exec "$nsr1" nft flush table netdev dscpmangle
417else
418	echo "SKIP: Could not load netdev:egress for veth1"
419fi
420
421	# partial.  If flowtable really works, then both dscp-is-0 and dscp-is-cs3
422	# counters should have seen packets (before and after ft offload kicks in).
423	ip netns exec "$nsr1" nft -a insert rule inet filter forward ip dscp set cs3
424	test_tcp_forwarding_ip "$1" "$2"  10.0.2.99 12345
425	check_dscp "dscp_fwd"
426}
427
428test_tcp_forwarding_nat()
429{
430	local lret
431	local pmtu
432
433	test_tcp_forwarding_ip "$1" "$2" 10.0.2.99 12345
434	lret=$?
435
436	pmtu=$3
437	what=$4
438
439	if [ "$lret" -eq 0 ] ; then
440		if [ "$pmtu" -eq 1 ] ;then
441			check_counters "flow offload for ns1/ns2 with masquerade and pmtu discovery $what"
442		else
443			echo "PASS: flow offload for ns1/ns2 with masquerade $what"
444		fi
445
446		test_tcp_forwarding_ip "$1" "$2" 10.6.6.6 1666
447		lret=$?
448		if [ "$pmtu" -eq 1 ] ;then
449			check_counters "flow offload for ns1/ns2 with dnat and pmtu discovery $what"
450		elif [ "$lret" -eq 0 ] ; then
451			echo "PASS: flow offload for ns1/ns2 with dnat $what"
452		fi
453	fi
454
455	return $lret
456}
457
458make_file "$nsin"
459
460# First test:
461# No PMTU discovery, nsr1 is expected to fragment packets from ns1 to ns2 as needed.
462# Due to MTU mismatch in both directions, all packets (except small packets like pure
463# acks) have to be handled by normal forwarding path.  Therefore, packet counters
464# are not checked.
465if test_tcp_forwarding "$ns1" "$ns2"; then
466	echo "PASS: flow offloaded for ns1/ns2"
467else
468	echo "FAIL: flow offload for ns1/ns2:" 1>&2
469	ip netns exec "$nsr1" nft list ruleset
470	ret=1
471fi
472
473# delete default route, i.e. ns2 won't be able to reach ns1 and
474# will depend on ns1 being masqueraded in nsr1.
475# expect ns1 has nsr1 address.
476ip -net "$ns2" route del default via 10.0.2.1
477ip -net "$ns2" route del default via dead:2::1
478ip -net "$ns2" route add 192.168.10.1 via 10.0.2.1
479
480# Second test:
481# Same, but with NAT enabled.  Same as in first test: we expect normal forward path
482# to handle most packets.
483ip netns exec "$nsr1" nft -f - <<EOF
484table ip nat {
485   chain prerouting {
486      type nat hook prerouting priority 0; policy accept;
487      meta iif "veth0" ip daddr 10.6.6.6 tcp dport 1666 counter dnat ip to 10.0.2.99:12345
488   }
489
490   chain postrouting {
491      type nat hook postrouting priority 0; policy accept;
492      meta oifname "veth1" counter masquerade
493   }
494}
495EOF
496
497if ! test_tcp_forwarding_set_dscp "$ns1" "$ns2" 0 ""; then
498	echo "FAIL: flow offload for ns1/ns2 with dscp update" 1>&2
499	exit 0
500fi
501
502if ! test_tcp_forwarding_nat "$ns1" "$ns2" 0 ""; then
503	echo "FAIL: flow offload for ns1/ns2 with NAT" 1>&2
504	ip netns exec "$nsr1" nft list ruleset
505	ret=1
506fi
507
508# Third test:
509# Same as second test, but with PMTU discovery enabled. This
510# means that we expect the fastpath to handle packets as soon
511# as the endpoints adjust the packet size.
512ip netns exec "$ns1" sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
513ip netns exec "$ns2" sysctl net.ipv4.ip_no_pmtu_disc=0 > /dev/null
514
515# reset counters.
516# With pmtu in-place we'll also check that nft counters
517# are lower than file size and packets were forwarded via flowtable layer.
518# For earlier tests (large mtus), packets cannot be handled via flowtable
519# (except pure acks and other small packets).
520ip netns exec "$nsr1" nft reset counters table inet filter >/dev/null
521
522if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 ""; then
523	echo "FAIL: flow offload for ns1/ns2 with NAT and pmtu discovery" 1>&2
524	ip netns exec "$nsr1" nft list ruleset
525fi
526
527# Another test:
528# Add bridge interface br0 to Router1, with NAT enabled.
529test_bridge() {
530if ! ip -net "$nsr1" link add name br0 type bridge 2>/dev/null;then
531	echo "SKIP: could not add bridge br0"
532	[ "$ret" -eq 0 ] && ret=$ksft_skip
533	return
534fi
535ip -net "$nsr1" addr flush dev veth0
536ip -net "$nsr1" link set up dev veth0
537ip -net "$nsr1" link set veth0 master br0
538ip -net "$nsr1" addr add 10.0.1.1/24 dev br0
539ip -net "$nsr1" addr add dead:1::1/64 dev br0 nodad
540ip -net "$nsr1" link set up dev br0
541
542ip netns exec "$nsr1" sysctl net.ipv4.conf.br0.forwarding=1 > /dev/null
543
544# br0 with NAT enabled.
545ip netns exec "$nsr1" nft -f - <<EOF
546flush table ip nat
547table ip nat {
548   chain prerouting {
549      type nat hook prerouting priority 0; policy accept;
550      meta iif "br0" ip daddr 10.6.6.6 tcp dport 1666 counter dnat ip to 10.0.2.99:12345
551   }
552
553   chain postrouting {
554      type nat hook postrouting priority 0; policy accept;
555      meta oifname "veth1" counter masquerade
556   }
557}
558EOF
559
560if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "on bridge"; then
561	echo "FAIL: flow offload for ns1/ns2 with bridge NAT" 1>&2
562	ip netns exec "$nsr1" nft list ruleset
563	ret=1
564fi
565
566
567# Another test:
568# Add bridge interface br0 to Router1, with NAT and VLAN.
569ip -net "$nsr1" link set veth0 nomaster
570ip -net "$nsr1" link set down dev veth0
571ip -net "$nsr1" link add link veth0 name veth0.10 type vlan id 10
572ip -net "$nsr1" link set up dev veth0
573ip -net "$nsr1" link set up dev veth0.10
574ip -net "$nsr1" link set veth0.10 master br0
575
576ip -net "$ns1" addr flush dev eth0
577ip -net "$ns1" link add link eth0 name eth0.10 type vlan id 10
578ip -net "$ns1" link set eth0 up
579ip -net "$ns1" link set eth0.10 up
580ip -net "$ns1" addr add 10.0.1.99/24 dev eth0.10
581ip -net "$ns1" route add default via 10.0.1.1
582ip -net "$ns1" addr add dead:1::99/64 dev eth0.10 nodad
583
584if ! test_tcp_forwarding_nat "$ns1" "$ns2" 1 "bridge and VLAN"; then
585	echo "FAIL: flow offload for ns1/ns2 with bridge NAT and VLAN" 1>&2
586	ip netns exec "$nsr1" nft list ruleset
587	ret=1
588fi
589
590# restore test topology (remove bridge and VLAN)
591ip -net "$nsr1" link set veth0 nomaster
592ip -net "$nsr1" link set veth0 down
593ip -net "$nsr1" link set veth0.10 down
594ip -net "$nsr1" link delete veth0.10 type vlan
595ip -net "$nsr1" link delete br0 type bridge
596ip -net "$ns1" addr flush dev eth0.10
597ip -net "$ns1" link set eth0.10 down
598ip -net "$ns1" link set eth0 down
599ip -net "$ns1" link delete eth0.10 type vlan
600
601# restore address in ns1 and nsr1
602ip -net "$ns1" link set eth0 up
603ip -net "$ns1" addr add 10.0.1.99/24 dev eth0
604ip -net "$ns1" route add default via 10.0.1.1
605ip -net "$ns1" addr add dead:1::99/64 dev eth0 nodad
606ip -net "$ns1" route add default via dead:1::1
607ip -net "$nsr1" addr add 10.0.1.1/24 dev veth0
608ip -net "$nsr1" addr add dead:1::1/64 dev veth0 nodad
609ip -net "$nsr1" link set up dev veth0
610}
611
612test_bridge
613
614KEY_SHA="0x"$(ps -af | sha1sum | cut -d " " -f 1)
615KEY_AES="0x"$(ps -af | md5sum | cut -d " " -f 1)
616SPI1=$RANDOM
617SPI2=$RANDOM
618
619if [ $SPI1 -eq $SPI2 ]; then
620	SPI2=$((SPI2+1))
621fi
622
623do_esp() {
624    local ns=$1
625    local me=$2
626    local remote=$3
627    local lnet=$4
628    local rnet=$5
629    local spi_out=$6
630    local spi_in=$7
631
632    ip -net "$ns" xfrm state add src "$remote" dst "$me" proto esp spi "$spi_in"  enc aes "$KEY_AES"  auth sha1 "$KEY_SHA" mode tunnel sel src "$rnet" dst "$lnet"
633    ip -net "$ns" xfrm state add src "$me"  dst "$remote" proto esp spi "$spi_out" enc aes "$KEY_AES" auth sha1 "$KEY_SHA" mode tunnel sel src "$lnet" dst "$rnet"
634
635    # to encrypt packets as they go out (includes forwarded packets that need encapsulation)
636    ip -net "$ns" xfrm policy add src "$lnet" dst "$rnet" dir out tmpl src "$me" dst "$remote" proto esp mode tunnel priority 1 action allow
637    # to fwd decrypted packets after esp processing:
638    ip -net "$ns" xfrm policy add src "$rnet" dst "$lnet" dir fwd tmpl src "$remote" dst "$me" proto esp mode tunnel priority 1 action allow
639}
640
641do_esp "$nsr1" 192.168.10.1 192.168.10.2 10.0.1.0/24 10.0.2.0/24 "$SPI1" "$SPI2"
642
643do_esp "$nsr2" 192.168.10.2 192.168.10.1 10.0.2.0/24 10.0.1.0/24 "$SPI2" "$SPI1"
644
645ip netns exec "$nsr1" nft delete table ip nat
646
647# restore default routes
648ip -net "$ns2" route del 192.168.10.1 via 10.0.2.1
649ip -net "$ns2" route add default via 10.0.2.1
650ip -net "$ns2" route add default via dead:2::1
651
652if test_tcp_forwarding "$ns1" "$ns2"; then
653	check_counters "ipsec tunnel mode for ns1/ns2"
654else
655	echo "FAIL: ipsec tunnel mode for ns1/ns2"
656	ip netns exec "$nsr1" nft list ruleset 1>&2
657	ip netns exec "$nsr1" cat /proc/net/xfrm_stat 1>&2
658fi
659
660if [ "$1" = "" ]; then
661	low=1280
662	mtu=$((65536 - low))
663	o=$(((RANDOM%mtu) + low))
664	l=$(((RANDOM%mtu) + low))
665	r=$(((RANDOM%mtu) + low))
666
667	echo "re-run with random mtus: -o $o -l $l -r $r"
668	$0 -o "$o" -l "$l" -r "$r"
669fi
670
671exit $ret
672