• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3#
4# nft_concat_range.sh - Tests for sets with concatenation of ranged fields
5#
6# Copyright (c) 2019 Red Hat GmbH
7#
8# Author: Stefano Brivio <sbrivio@redhat.com>
9#
10# shellcheck disable=SC2154,SC2034,SC2016,SC2030,SC2031
11# ^ Configuration and templates sourced with eval, counters reused in subshells
12
13KSELFTEST_SKIP=4
14
15# Available test groups:
16# - reported_issues: check for issues that were reported in the past
17# - correctness: check that packets match given entries, and only those
18# - concurrency: attempt races between insertion, deletion and lookup
19# - timeout: check that packets match entries until they expire
20# - performance: estimate matching rate, compare with rbtree and hash baselines
21TESTS="reported_issues correctness concurrency timeout"
22[ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
23
24# Set types, defined by TYPE_ variables below
25TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
26       net_port_net net_mac net_mac_icmp net6_mac_icmp net6_port_net6_port
27       net_port_mac_proto_net"
28
29# Reported bugs, also described by TYPE_ variables below
30BUGS="flush_remove_add reload"
31
32# List of possible paths to pktgen script from kernel tree for performance tests
33PKTGEN_SCRIPT_PATHS="
34	../../../../samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
35	pktgen/pktgen_bench_xmit_mode_netif_receive.sh"
36
37# Definition of set types:
38# display	display text for test report
39# type_spec	nftables set type specifier
40# chain_spec	nftables type specifier for rules mapping to set
41# dst		call sequence of format_*() functions for destination fields
42# src		call sequence of format_*() functions for source fields
43# start		initial integer used to generate addresses and ports
44# count		count of entries to generate and match
45# src_delta	number summed to destination generator for source fields
46# tools		list of tools for correctness and timeout tests, any can be used
47# proto		L4 protocol of test packets
48#
49# race_repeat	race attempts per thread, 0 disables concurrency test for type
50# flood_tools	list of tools for concurrency tests, any can be used
51# flood_proto	L4 protocol of test packets for concurrency tests
52# flood_spec	nftables type specifier for concurrency tests
53#
54# perf_duration	duration of single pktgen injection test
55# perf_spec	nftables type specifier for performance tests
56# perf_dst	format_*() functions for destination fields in performance test
57# perf_src	format_*() functions for source fields in performance test
58# perf_entries	number of set entries for performance test
59# perf_proto	L3 protocol of test packets
60TYPE_net_port="
61display		net,port
62type_spec	ipv4_addr . inet_service
63chain_spec	ip daddr . udp dport
64dst		addr4 port
65src
66start		1
67count		5
68src_delta	2000
69tools		sendip nc bash
70proto		udp
71
72race_repeat	3
73flood_tools	iperf3 iperf netperf
74flood_proto	udp
75flood_spec	ip daddr . udp dport
76
77perf_duration	5
78perf_spec	ip daddr . udp dport
79perf_dst	addr4 port
80perf_src
81perf_entries	1000
82perf_proto	ipv4
83"
84
85TYPE_port_net="
86display		port,net
87type_spec	inet_service . ipv4_addr
88chain_spec	udp dport . ip daddr
89dst		port addr4
90src
91start		1
92count		5
93src_delta	2000
94tools		sendip nc bash
95proto		udp
96
97race_repeat	3
98flood_tools	iperf3 iperf netperf
99flood_proto	udp
100flood_spec	udp dport . ip daddr
101
102perf_duration	5
103perf_spec	udp dport . ip daddr
104perf_dst	port addr4
105perf_src
106perf_entries	100
107perf_proto	ipv4
108"
109
110TYPE_net6_port="
111display		net6,port
112type_spec	ipv6_addr . inet_service
113chain_spec	ip6 daddr . udp dport
114dst		addr6 port
115src
116start		10
117count		5
118src_delta	2000
119tools		sendip nc bash
120proto		udp6
121
122race_repeat	3
123flood_tools	iperf3 iperf netperf
124flood_proto	tcp6
125flood_spec	ip6 daddr . udp dport
126
127perf_duration	5
128perf_spec	ip6 daddr . udp dport
129perf_dst	addr6 port
130perf_src
131perf_entries	1000
132perf_proto	ipv6
133"
134
135TYPE_port_proto="
136display		port,proto
137type_spec	inet_service . inet_proto
138chain_spec	udp dport . meta l4proto
139dst		port proto
140src
141start		1
142count		5
143src_delta	2000
144tools		sendip nc bash
145proto		udp
146
147race_repeat	0
148
149perf_duration	5
150perf_spec	udp dport . meta l4proto
151perf_dst	port proto
152perf_src
153perf_entries	30000
154perf_proto	ipv4
155"
156
157TYPE_net6_port_mac="
158display		net6,port,mac
159type_spec	ipv6_addr . inet_service . ether_addr
160chain_spec	ip6 daddr . udp dport . ether saddr
161dst		addr6 port
162src		mac
163start		10
164count		5
165src_delta	2000
166tools		sendip nc bash
167proto		udp6
168
169race_repeat	0
170
171perf_duration	5
172perf_spec	ip6 daddr . udp dport . ether daddr
173perf_dst	addr6 port mac
174perf_src
175perf_entries	10
176perf_proto	ipv6
177"
178
179TYPE_net6_port_mac_proto="
180display		net6,port,mac,proto
181type_spec	ipv6_addr . inet_service . ether_addr . inet_proto
182chain_spec	ip6 daddr . udp dport . ether saddr . meta l4proto
183dst		addr6 port
184src		mac proto
185start		10
186count		5
187src_delta	2000
188tools		sendip nc bash
189proto		udp6
190
191race_repeat	0
192
193perf_duration	5
194perf_spec	ip6 daddr . udp dport . ether daddr . meta l4proto
195perf_dst	addr6 port mac proto
196perf_src
197perf_entries	1000
198perf_proto	ipv6
199"
200
201TYPE_net_port_net="
202display		net,port,net
203type_spec	ipv4_addr . inet_service . ipv4_addr
204chain_spec	ip daddr . udp dport . ip saddr
205dst		addr4 port
206src		addr4
207start		1
208count		5
209src_delta	2000
210tools		sendip nc bash
211proto		udp
212
213race_repeat	3
214flood_tools	iperf3 iperf netperf
215flood_proto	tcp
216flood_spec	ip daddr . udp dport . ip saddr
217
218perf_duration	0
219"
220
221TYPE_net6_port_net6_port="
222display		net6,port,net6,port
223type_spec	ipv6_addr . inet_service . ipv6_addr . inet_service
224chain_spec	ip6 daddr . udp dport . ip6 saddr . udp sport
225dst		addr6 port
226src		addr6 port
227start		10
228count		5
229src_delta	2000
230tools		sendip nc
231proto		udp6
232
233race_repeat	3
234flood_tools	iperf3 iperf netperf
235flood_proto	tcp6
236flood_spec	ip6 daddr . tcp dport . ip6 saddr . tcp sport
237
238perf_duration	0
239"
240
241TYPE_net_port_mac_proto_net="
242display		net,port,mac,proto,net
243type_spec	ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr
244chain_spec	ip daddr . udp dport . ether saddr . meta l4proto . ip saddr
245dst		addr4 port
246src		mac proto addr4
247start		1
248count		5
249src_delta	2000
250tools		sendip nc bash
251proto		udp
252
253race_repeat	0
254
255perf_duration	0
256"
257
258TYPE_net_mac="
259display		net,mac
260type_spec	ipv4_addr . ether_addr
261chain_spec	ip daddr . ether saddr
262dst		addr4
263src		mac
264start		1
265count		5
266src_delta	2000
267tools		sendip nc bash
268proto		udp
269
270race_repeat	0
271
272perf_duration	5
273perf_spec	ip daddr . ether daddr
274perf_dst	addr4 mac
275perf_src
276perf_entries	1000
277perf_proto	ipv4
278"
279
280TYPE_net_mac_icmp="
281display		net,mac - ICMP
282type_spec	ipv4_addr . ether_addr
283chain_spec	ip daddr . ether saddr
284dst		addr4
285src		mac
286start		1
287count		5
288src_delta	2000
289tools		ping
290proto		icmp
291
292race_repeat	0
293
294perf_duration	0
295"
296
297TYPE_net6_mac_icmp="
298display		net6,mac - ICMPv6
299type_spec	ipv6_addr . ether_addr
300chain_spec	ip6 daddr . ether saddr
301dst		addr6
302src		mac
303start		10
304count		50
305src_delta	2000
306tools		ping
307proto		icmp6
308
309race_repeat	0
310
311perf_duration	0
312"
313
314TYPE_net_port_proto_net="
315display		net,port,proto,net
316type_spec	ipv4_addr . inet_service . inet_proto . ipv4_addr
317chain_spec	ip daddr . udp dport . meta l4proto . ip saddr
318dst		addr4 port proto
319src		addr4
320start		1
321count		5
322src_delta	2000
323tools		sendip nc
324proto		udp
325
326race_repeat	3
327flood_tools	iperf3 iperf netperf
328flood_proto	tcp
329flood_spec	ip daddr . tcp dport . meta l4proto . ip saddr
330
331perf_duration	0
332"
333
334# Definition of tests for bugs reported in the past:
335# display	display text for test report
336TYPE_flush_remove_add="
337display		Add two elements, flush, re-add
338"
339
340TYPE_reload="
341display		net,mac with reload
342type_spec	ipv4_addr . ether_addr
343chain_spec	ip daddr . ether saddr
344dst		addr4
345src		mac
346start		1
347count		1
348src_delta	2000
349tools		sendip nc bash
350proto		udp
351
352race_repeat	0
353
354perf_duration	0
355"
356
357# Set template for all tests, types and rules are filled in depending on test
358set_template='
359flush ruleset
360
361table inet filter {
362	counter test {
363		packets 0 bytes 0
364	}
365
366	set test {
367		type ${type_spec}
368		flags interval,timeout
369	}
370
371	chain input {
372		type filter hook prerouting priority 0; policy accept;
373		${chain_spec} @test counter name \"test\"
374	}
375}
376
377table netdev perf {
378	counter test {
379		packets 0 bytes 0
380	}
381
382	counter match {
383		packets 0 bytes 0
384	}
385
386	set test {
387		type ${type_spec}
388		flags interval
389	}
390
391	set norange {
392		type ${type_spec}
393	}
394
395	set noconcat {
396		type ${type_spec%% *}
397		flags interval
398	}
399
400	chain test {
401		type filter hook ingress device veth_a priority 0;
402	}
403}
404'
405
406err_buf=
407info_buf=
408
409# Append string to error buffer
410err() {
411	err_buf="${err_buf}${1}
412"
413}
414
415# Append string to information buffer
416info() {
417	info_buf="${info_buf}${1}
418"
419}
420
421# Flush error buffer to stdout
422err_flush() {
423	printf "%s" "${err_buf}"
424	err_buf=
425}
426
427# Flush information buffer to stdout
428info_flush() {
429	printf "%s" "${info_buf}"
430	info_buf=
431}
432
433# Setup veth pair: this namespace receives traffic, B generates it
434setup_veth() {
435	ip netns add B
436	ip link add veth_a type veth peer name veth_b || return 1
437
438	ip link set veth_a up
439	ip link set veth_b netns B
440
441	ip -n B link set veth_b up
442
443	ip addr add dev veth_a 10.0.0.1
444	ip route add default dev veth_a
445
446	ip -6 addr add fe80::1/64 dev veth_a nodad
447	ip -6 addr add 2001:db8::1/64 dev veth_a nodad
448	ip -6 route add default dev veth_a
449
450	ip -n B route add default dev veth_b
451
452	ip -6 -n B addr add fe80::2/64 dev veth_b nodad
453	ip -6 -n B addr add 2001:db8::2/64 dev veth_b nodad
454	ip -6 -n B route add default dev veth_b
455
456	B() {
457		ip netns exec B "$@" >/dev/null 2>&1
458	}
459
460	sleep 2
461}
462
463# Fill in set template and initialise set
464setup_set() {
465	eval "echo \"${set_template}\"" | nft -f -
466}
467
468# Check that at least one of the needed tools is available
469check_tools() {
470	[ -z "${tools}" ] && return 0
471
472	__tools=
473	for tool in ${tools}; do
474		if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
475		   ! nc -u -w0 1.1.1.1 1 2>/dev/null; then
476			# Some GNU netcat builds might not support IPv6
477			__tools="${__tools} netcat-openbsd"
478			continue
479		fi
480		__tools="${__tools} ${tool}"
481
482		command -v "${tool}" >/dev/null && return 0
483	done
484	err "need one of:${__tools}, skipping" && return 1
485}
486
487# Set up function to send ICMP packets
488setup_send_icmp() {
489	send_icmp() {
490		B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1
491	}
492}
493
494# Set up function to send ICMPv6 packets
495setup_send_icmp6() {
496	if command -v ping6 >/dev/null; then
497		send_icmp6() {
498			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
499				2>/dev/null
500			B ping6 -q -c1 -W1 "${dst_addr6}"
501		}
502	else
503		send_icmp6() {
504			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
505				2>/dev/null
506			B ping -q -6 -c1 -W1 "${dst_addr6}"
507		}
508	fi
509}
510
511# Set up function to send single UDP packets on IPv4
512setup_send_udp() {
513	if command -v sendip >/dev/null; then
514		send_udp() {
515			[ -n "${src_port}" ] && src_port="-us ${src_port}"
516			[ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
517			[ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}"
518
519			# shellcheck disable=SC2086 # sendip needs split options
520			B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \
521						${dst_port} "${dst_addr4}"
522
523			src_port=
524			dst_port=
525			src_addr4=
526		}
527	elif command -v nc >/dev/null; then
528		if nc -u -w0 1.1.1.1 1 2>/dev/null; then
529			# OpenBSD netcat
530			nc_opt="-w0"
531		else
532			# GNU netcat
533			nc_opt="-q0"
534		fi
535
536		send_udp() {
537			if [ -n "${src_addr4}" ]; then
538				B ip addr add "${src_addr4}" dev veth_b
539				__src_addr4="-s ${src_addr4}"
540			fi
541			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
542			[ -n "${src_port}" ] && src_port="-p ${src_port}"
543
544			echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \
545				  "${src_port}" "${dst_addr4}" "${dst_port}"
546
547			src_addr4=
548			src_port=
549		}
550	elif [ -z "$(bash -c 'type -p')" ]; then
551		send_udp() {
552			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
553			if [ -n "${src_addr4}" ]; then
554				B ip addr add "${src_addr4}/16" dev veth_b
555				B ip route add default dev veth_b
556			fi
557
558			B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}"
559
560			if [ -n "${src_addr4}" ]; then
561				B ip addr del "${src_addr4}/16" dev veth_b
562			fi
563			src_addr4=
564		}
565	else
566		return 1
567	fi
568}
569
570# Set up function to send single UDP packets on IPv6
571setup_send_udp6() {
572	if command -v sendip >/dev/null; then
573		send_udp6() {
574			[ -n "${src_port}" ] && src_port="-us ${src_port}"
575			[ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
576			if [ -n "${src_addr6}" ]; then
577				src_addr6="-6s ${src_addr6}"
578			else
579				src_addr6="-6s 2001:db8::2"
580			fi
581			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
582				2>/dev/null
583
584			# shellcheck disable=SC2086 # this needs split options
585			B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \
586						${dst_port} "${dst_addr6}"
587
588			src_port=
589			dst_port=
590			src_addr6=
591		}
592	elif command -v nc >/dev/null && nc -u -w0 1.1.1.1 1 2>/dev/null; then
593		# GNU netcat might not work with IPv6, try next tool
594		send_udp6() {
595			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
596				2>/dev/null
597			if [ -n "${src_addr6}" ]; then
598				B ip addr add "${src_addr6}" dev veth_b nodad
599			else
600				src_addr6="2001:db8::2"
601			fi
602			[ -n "${src_port}" ] && src_port="-p ${src_port}"
603
604			# shellcheck disable=SC2086 # this needs split options
605			echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \
606					       ${dst_addr6} ${dst_port}
607
608			src_addr6=
609			src_port=
610		}
611	elif [ -z "$(bash -c 'type -p')" ]; then
612		send_udp6() {
613			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
614				2>/dev/null
615			B ip addr add "${src_addr6}" dev veth_b nodad
616			B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}"
617			ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null
618		}
619	else
620		return 1
621	fi
622}
623
624# Set up function to send TCP traffic on IPv4
625setup_flood_tcp() {
626	if command -v iperf3 >/dev/null; then
627		flood_tcp() {
628			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
629			if [ -n "${src_addr4}" ]; then
630				B ip addr add "${src_addr4}/16" dev veth_b
631				src_addr4="-B ${src_addr4}"
632			else
633				B ip addr add dev veth_b 10.0.0.2
634				src_addr4="-B 10.0.0.2"
635			fi
636			if [ -n "${src_port}" ]; then
637				src_port="--cport ${src_port}"
638			fi
639			B ip route add default dev veth_b 2>/dev/null
640			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
641
642			# shellcheck disable=SC2086 # this needs split options
643			iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
644			sleep 2
645
646			# shellcheck disable=SC2086 # this needs split options
647			B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \
648				${src_addr4} -l16 -t 1000
649
650			src_addr4=
651			src_port=
652			dst_port=
653		}
654	elif command -v iperf >/dev/null; then
655		flood_tcp() {
656			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
657			if [ -n "${src_addr4}" ]; then
658				B ip addr add "${src_addr4}/16" dev veth_b
659				src_addr4="-B ${src_addr4}"
660			else
661				B ip addr add dev veth_b 10.0.0.2 2>/dev/null
662				src_addr4="-B 10.0.0.2"
663			fi
664			if [ -n "${src_port}" ]; then
665				src_addr4="${src_addr4}:${src_port}"
666			fi
667			B ip route add default dev veth_b
668			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
669
670			# shellcheck disable=SC2086 # this needs split options
671			iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
672			sleep 2
673
674			# shellcheck disable=SC2086 # this needs split options
675			B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \
676				-l20 -t 1000
677
678			src_addr4=
679			src_port=
680			dst_port=
681		}
682	elif command -v netperf >/dev/null; then
683		flood_tcp() {
684			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
685			if [ -n "${src_addr4}" ]; then
686				B ip addr add "${src_addr4}/16" dev veth_b
687			else
688				B ip addr add dev veth_b 10.0.0.2
689				src_addr4="10.0.0.2"
690			fi
691			if [ -n "${src_port}" ]; then
692				dst_port="${dst_port},${src_port}"
693			fi
694			B ip route add default dev veth_b
695			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
696
697			# shellcheck disable=SC2086 # this needs split options
698			netserver -4 ${dst_port} -L "${dst_addr4}" \
699				>/dev/null 2>&1
700			sleep 2
701
702			# shellcheck disable=SC2086 # this needs split options
703			B netperf -4 -H "${dst_addr4}" ${dst_port} \
704				-L "${src_addr4}" -l 1000 -t TCP_STREAM
705
706			src_addr4=
707			src_port=
708			dst_port=
709		}
710	else
711		return 1
712	fi
713}
714
715# Set up function to send TCP traffic on IPv6
716setup_flood_tcp6() {
717	if command -v iperf3 >/dev/null; then
718		flood_tcp6() {
719			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
720			if [ -n "${src_addr6}" ]; then
721				B ip addr add "${src_addr6}" dev veth_b nodad
722				src_addr6="-B ${src_addr6}"
723			else
724				src_addr6="-B 2001:db8::2"
725			fi
726			if [ -n "${src_port}" ]; then
727				src_port="--cport ${src_port}"
728			fi
729			B ip route add default dev veth_b
730			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
731				2>/dev/null
732
733			# shellcheck disable=SC2086 # this needs split options
734			iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
735			sleep 2
736
737			# shellcheck disable=SC2086 # this needs split options
738			B iperf3 -c "${dst_addr6}" ${dst_port} \
739				${src_port} ${src_addr6} -l16 -t 1000
740
741			src_addr6=
742			src_port=
743			dst_port=
744		}
745	elif command -v iperf >/dev/null; then
746		flood_tcp6() {
747			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
748			if [ -n "${src_addr6}" ]; then
749				B ip addr add "${src_addr6}" dev veth_b nodad
750				src_addr6="-B ${src_addr6}"
751			else
752				src_addr6="-B 2001:db8::2"
753			fi
754			if [ -n "${src_port}" ]; then
755				src_addr6="${src_addr6}:${src_port}"
756			fi
757			B ip route add default dev veth_b
758			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
759				2>/dev/null
760
761			# shellcheck disable=SC2086 # this needs split options
762			iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
763			sleep 2
764
765			# shellcheck disable=SC2086 # this needs split options
766			B iperf -c "${dst_addr6}" -V ${dst_port} \
767				${src_addr6} -l1 -t 1000
768
769			src_addr6=
770			src_port=
771			dst_port=
772		}
773	elif command -v netperf >/dev/null; then
774		flood_tcp6() {
775			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
776			if [ -n "${src_addr6}" ]; then
777				B ip addr add "${src_addr6}" dev veth_b nodad
778			else
779				src_addr6="2001:db8::2"
780			fi
781			if [ -n "${src_port}" ]; then
782				dst_port="${dst_port},${src_port}"
783			fi
784			B ip route add default dev veth_b
785			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
786				2>/dev/null
787
788			# shellcheck disable=SC2086 # this needs split options
789			netserver -6 ${dst_port} -L "${dst_addr6}" \
790				>/dev/null 2>&1
791			sleep 2
792
793			# shellcheck disable=SC2086 # this needs split options
794			B netperf -6 -H "${dst_addr6}" ${dst_port} \
795				-L "${src_addr6}" -l 1000 -t TCP_STREAM
796
797			src_addr6=
798			src_port=
799			dst_port=
800		}
801	else
802		return 1
803	fi
804}
805
806# Set up function to send UDP traffic on IPv4
807setup_flood_udp() {
808	if command -v iperf3 >/dev/null; then
809		flood_udp() {
810			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
811			if [ -n "${src_addr4}" ]; then
812				B ip addr add "${src_addr4}/16" dev veth_b
813				src_addr4="-B ${src_addr4}"
814			else
815				B ip addr add dev veth_b 10.0.0.2 2>/dev/null
816				src_addr4="-B 10.0.0.2"
817			fi
818			if [ -n "${src_port}" ]; then
819				src_port="--cport ${src_port}"
820			fi
821			B ip route add default dev veth_b
822			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
823
824			# shellcheck disable=SC2086 # this needs split options
825			iperf3 -s -DB "${dst_addr4}" ${dst_port}
826			sleep 2
827
828			# shellcheck disable=SC2086 # this needs split options
829			B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \
830				${dst_port} ${src_port} ${src_addr4}
831
832			src_addr4=
833			src_port=
834			dst_port=
835		}
836	elif command -v iperf >/dev/null; then
837		flood_udp() {
838			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
839			if [ -n "${src_addr4}" ]; then
840				B ip addr add "${src_addr4}/16" dev veth_b
841				src_addr4="-B ${src_addr4}"
842			else
843				B ip addr add dev veth_b 10.0.0.2
844				src_addr4="-B 10.0.0.2"
845			fi
846			if [ -n "${src_port}" ]; then
847				src_addr4="${src_addr4}:${src_port}"
848			fi
849			B ip route add default dev veth_b
850			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
851
852			# shellcheck disable=SC2086 # this needs split options
853			iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
854			sleep 2
855
856			# shellcheck disable=SC2086 # this needs split options
857			B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \
858				${dst_port} ${src_addr4}
859
860			src_addr4=
861			src_port=
862			dst_port=
863		}
864	elif command -v netperf >/dev/null; then
865		flood_udp() {
866			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
867			if [ -n "${src_addr4}" ]; then
868				B ip addr add "${src_addr4}/16" dev veth_b
869			else
870				B ip addr add dev veth_b 10.0.0.2
871				src_addr4="10.0.0.2"
872			fi
873			if [ -n "${src_port}" ]; then
874				dst_port="${dst_port},${src_port}"
875			fi
876			B ip route add default dev veth_b
877			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
878
879			# shellcheck disable=SC2086 # this needs split options
880			netserver -4 ${dst_port} -L "${dst_addr4}" \
881				>/dev/null 2>&1
882			sleep 2
883
884			# shellcheck disable=SC2086 # this needs split options
885			B netperf -4 -H "${dst_addr4}" ${dst_port} \
886				-L "${src_addr4}" -l 1000 -t UDP_STREAM
887
888			src_addr4=
889			src_port=
890			dst_port=
891		}
892	else
893		return 1
894	fi
895}
896
897# Find pktgen script and set up function to start pktgen injection
898setup_perf() {
899	for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do
900		command -v "${pktgen_script_path}" >/dev/null && break
901	done
902	[ "${pktgen_script_path}" = "__notfound" ] && return 1
903
904	perf_ipv4() {
905		${pktgen_script_path} -s80 \
906			-i veth_a -d "${dst_addr4}" -p "${dst_port}" \
907			-m "${dst_mac}" \
908			-t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
909		perf_pid=$!
910	}
911	perf_ipv6() {
912		IP6=6 ${pktgen_script_path} -s100 \
913			-i veth_a -d "${dst_addr6}" -p "${dst_port}" \
914			-m "${dst_mac}" \
915			-t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
916		perf_pid=$!
917	}
918}
919
920# Clean up before each test
921cleanup() {
922	nft reset counter inet filter test	>/dev/null 2>&1
923	nft flush ruleset			>/dev/null 2>&1
924	ip link del dummy0			2>/dev/null
925	ip route del default			2>/dev/null
926	ip -6 route del default			2>/dev/null
927	ip netns del B				2>/dev/null
928	ip link del veth_a			2>/dev/null
929	timeout=
930	killall iperf3				2>/dev/null
931	killall iperf				2>/dev/null
932	killall netperf				2>/dev/null
933	killall netserver			2>/dev/null
934	rm -f ${tmp}
935	sleep 2
936}
937
938# Entry point for setup functions
939setup() {
940	if [ "$(id -u)" -ne 0 ]; then
941		echo "  need to run as root"
942		exit ${KSELFTEST_SKIP}
943	fi
944
945	cleanup
946	check_tools || return 1
947	for arg do
948		if ! eval setup_"${arg}"; then
949			err "  ${arg} not supported"
950			return 1
951		fi
952	done
953}
954
955# Format integer into IPv4 address, summing 10.0.0.5 (arbitrary) to it
956format_addr4() {
957	a=$((${1} + 16777216 * 10 + 5))
958	printf "%i.%i.%i.%i"						\
959	       "$((a / 16777216))" "$((a % 16777216 / 65536))"	\
960	       "$((a % 65536 / 256))" "$((a % 256))"
961}
962
963# Format integer into IPv6 address, summing 2001:db8:: to it
964format_addr6() {
965	printf "2001:db8::%04x:%04x" "$((${1} / 65536))" "$((${1} % 65536))"
966}
967
968# Format integer into EUI-48 address, summing 00:01:00:00:00:00 to it
969format_mac() {
970	printf "00:01:%02x:%02x:%02x:%02x" \
971	       "$((${1} / 16777216))" "$((${1} % 16777216 / 65536))"	\
972	       "$((${1} % 65536 / 256))" "$((${1} % 256))"
973}
974
975# Format integer into port, avoid 0 port
976format_port() {
977	printf "%i" "$((${1} % 65534 + 1))"
978}
979
980# Drop suffixed '6' from L4 protocol, if any
981format_proto() {
982	printf "%s" "${proto}" | tr -d 6
983}
984
985# Format destination and source fields into nft concatenated type
986format() {
987	__start=
988	__end=
989	__expr="{ "
990
991	for f in ${dst}; do
992		[ "${__expr}" != "{ " ] && __expr="${__expr} . "
993
994		__start="$(eval format_"${f}" "${start}")"
995		__end="$(eval format_"${f}" "${end}")"
996
997		if [ "${f}" = "proto" ]; then
998			__expr="${__expr}${__start}"
999		else
1000			__expr="${__expr}${__start}-${__end}"
1001		fi
1002	done
1003	for f in ${src}; do
1004		__expr="${__expr} . "
1005		__start="$(eval format_"${f}" "${srcstart}")"
1006		__end="$(eval format_"${f}" "${srcend}")"
1007
1008		if [ "${f}" = "proto" ]; then
1009			__expr="${__expr}${__start}"
1010		else
1011			__expr="${__expr}${__start}-${__end}"
1012		fi
1013	done
1014
1015	if [ -n "${timeout}" ]; then
1016		echo "${__expr} timeout ${timeout}s }"
1017	else
1018		echo "${__expr} }"
1019	fi
1020}
1021
1022# Format destination and source fields into nft type, start element only
1023format_norange() {
1024	__expr="{ "
1025
1026	for f in ${dst}; do
1027		[ "${__expr}" != "{ " ] && __expr="${__expr} . "
1028
1029		__expr="${__expr}$(eval format_"${f}" "${start}")"
1030	done
1031	for f in ${src}; do
1032		__expr="${__expr} . $(eval format_"${f}" "${start}")"
1033	done
1034
1035	echo "${__expr} }"
1036}
1037
1038# Format first destination field into nft type
1039format_noconcat() {
1040	for f in ${dst}; do
1041		__start="$(eval format_"${f}" "${start}")"
1042		__end="$(eval format_"${f}" "${end}")"
1043
1044		if [ "${f}" = "proto" ]; then
1045			echo "{ ${__start} }"
1046		else
1047			echo "{ ${__start}-${__end} }"
1048		fi
1049		return
1050	done
1051}
1052
1053# Add single entry to 'test' set in 'inet filter' table
1054add() {
1055	if ! nft add element inet filter test "${1}"; then
1056		err "Failed to add ${1} given ruleset:"
1057		err "$(nft -a list ruleset)"
1058		return 1
1059	fi
1060}
1061
1062# Format and output entries for sets in 'netdev perf' table
1063add_perf() {
1064	if [ "${1}" = "test" ]; then
1065		echo "add element netdev perf test $(format)"
1066	elif [ "${1}" = "norange" ]; then
1067		echo "add element netdev perf norange $(format_norange)"
1068	elif [ "${1}" = "noconcat" ]; then
1069		echo "add element netdev perf noconcat $(format_noconcat)"
1070	fi
1071}
1072
1073# Add single entry to 'norange' set in 'netdev perf' table
1074add_perf_norange() {
1075	if ! nft add element netdev perf norange "${1}"; then
1076		err "Failed to add ${1} given ruleset:"
1077		err "$(nft -a list ruleset)"
1078		return 1
1079	fi
1080}
1081
1082# Add single entry to 'noconcat' set in 'netdev perf' table
1083add_perf_noconcat() {
1084	if ! nft add element netdev perf noconcat "${1}"; then
1085		err "Failed to add ${1} given ruleset:"
1086		err "$(nft -a list ruleset)"
1087		return 1
1088	fi
1089}
1090
1091# Delete single entry from set
1092del() {
1093	if ! nft delete element inet filter test "${1}"; then
1094		err "Failed to delete ${1} given ruleset:"
1095		err "$(nft -a list ruleset)"
1096		return 1
1097	fi
1098}
1099
1100# Return packet count from 'test' counter in 'inet filter' table
1101count_packets() {
1102	found=0
1103	for token in $(nft list counter inet filter test); do
1104		[ ${found} -eq 1 ] && echo "${token}" && return
1105		[ "${token}" = "packets" ] && found=1
1106	done
1107}
1108
1109# Return packet count from 'test' counter in 'netdev perf' table
1110count_perf_packets() {
1111	found=0
1112	for token in $(nft list counter netdev perf test); do
1113		[ ${found} -eq 1 ] && echo "${token}" && return
1114		[ "${token}" = "packets" ] && found=1
1115	done
1116}
1117
1118# Set MAC addresses, send traffic according to specifier
1119flood() {
1120	ip link set veth_a address "$(format_mac "${1}")"
1121	ip -n B link set veth_b address "$(format_mac "${2}")"
1122
1123	for f in ${dst}; do
1124		eval dst_"$f"=\$\(format_\$f "${1}"\)
1125	done
1126	for f in ${src}; do
1127		eval src_"$f"=\$\(format_\$f "${2}"\)
1128	done
1129	eval flood_\$proto
1130}
1131
1132# Set MAC addresses, start pktgen injection
1133perf() {
1134	dst_mac="$(format_mac "${1}")"
1135	ip link set veth_a address "${dst_mac}"
1136
1137	for f in ${dst}; do
1138		eval dst_"$f"=\$\(format_\$f "${1}"\)
1139	done
1140	for f in ${src}; do
1141		eval src_"$f"=\$\(format_\$f "${2}"\)
1142	done
1143	eval perf_\$perf_proto
1144}
1145
1146# Set MAC addresses, send single packet, check that it matches, reset counter
1147send_match() {
1148	ip link set veth_a address "$(format_mac "${1}")"
1149	ip -n B link set veth_b address "$(format_mac "${2}")"
1150
1151	for f in ${dst}; do
1152		eval dst_"$f"=\$\(format_\$f "${1}"\)
1153	done
1154	for f in ${src}; do
1155		eval src_"$f"=\$\(format_\$f "${2}"\)
1156	done
1157	eval send_\$proto
1158	if [ "$(count_packets)" != "1" ]; then
1159		err "${proto} packet to:"
1160		err "  $(for f in ${dst}; do
1161			 eval format_\$f "${1}"; printf ' '; done)"
1162		err "from:"
1163		err "  $(for f in ${src}; do
1164			 eval format_\$f "${2}"; printf ' '; done)"
1165		err "should have matched ruleset:"
1166		err "$(nft -a list ruleset)"
1167		return 1
1168	fi
1169	nft reset counter inet filter test >/dev/null
1170}
1171
1172# Set MAC addresses, send single packet, check that it doesn't match
1173send_nomatch() {
1174	ip link set veth_a address "$(format_mac "${1}")"
1175	ip -n B link set veth_b address "$(format_mac "${2}")"
1176
1177	for f in ${dst}; do
1178		eval dst_"$f"=\$\(format_\$f "${1}"\)
1179	done
1180	for f in ${src}; do
1181		eval src_"$f"=\$\(format_\$f "${2}"\)
1182	done
1183	eval send_\$proto
1184	if [ "$(count_packets)" != "0" ]; then
1185		err "${proto} packet to:"
1186		err "  $(for f in ${dst}; do
1187			 eval format_\$f "${1}"; printf ' '; done)"
1188		err "from:"
1189		err "  $(for f in ${src}; do
1190			 eval format_\$f "${2}"; printf ' '; done)"
1191		err "should not have matched ruleset:"
1192		err "$(nft -a list ruleset)"
1193		return 1
1194	fi
1195}
1196
1197# Correctness test template:
1198# - add ranged element, check that packets match it
1199# - check that packets outside range don't match it
1200# - remove some elements, check that packets don't match anymore
1201test_correctness() {
1202	setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1203
1204	range_size=1
1205	for i in $(seq "${start}" $((start + count))); do
1206		end=$((start + range_size))
1207
1208		# Avoid negative or zero-sized port ranges
1209		if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1210			start=${end}
1211			end=$((end + 1))
1212		fi
1213		srcstart=$((start + src_delta))
1214		srcend=$((end + src_delta))
1215
1216		add "$(format)" || return 1
1217		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1218			send_match "${j}" $((j + src_delta)) || return 1
1219		done
1220		send_nomatch $((end + 1)) $((end + 1 + src_delta)) || return 1
1221
1222		# Delete elements now and then
1223		if [ $((i % 3)) -eq 0 ]; then
1224			del "$(format)" || return 1
1225			for j in $(seq ${start} \
1226				   $((range_size / 2 + 1)) ${end}); do
1227				send_nomatch "${j}" $((j + src_delta)) \
1228					|| return 1
1229			done
1230		fi
1231
1232		range_size=$((range_size + 1))
1233		start=$((end + range_size))
1234	done
1235}
1236
1237# Concurrency test template:
1238# - add all the elements
1239# - start a thread for each physical thread that:
1240#   - adds all the elements
1241#   - flushes the set
1242#   - adds all the elements
1243#   - flushes the entire ruleset
1244#   - adds the set back
1245#   - adds all the elements
1246#   - delete all the elements
1247test_concurrency() {
1248	proto=${flood_proto}
1249	tools=${flood_tools}
1250	chain_spec=${flood_spec}
1251	setup veth flood_"${proto}" set || return ${KSELFTEST_SKIP}
1252
1253	range_size=1
1254	cstart=${start}
1255	flood_pids=
1256	for i in $(seq ${start} $((start + count))); do
1257		end=$((start + range_size))
1258		srcstart=$((start + src_delta))
1259		srcend=$((end + src_delta))
1260
1261		add "$(format)" || return 1
1262
1263		flood "${i}" $((i + src_delta)) & flood_pids="${flood_pids} $!"
1264
1265		range_size=$((range_size + 1))
1266		start=$((end + range_size))
1267	done
1268
1269	sleep 10
1270
1271	pids=
1272	for c in $(seq 1 "$(nproc)"); do (
1273		for r in $(seq 1 "${race_repeat}"); do
1274			range_size=1
1275
1276			# $start needs to be local to this subshell
1277			# shellcheck disable=SC2030
1278			start=${cstart}
1279			for i in $(seq ${start} $((start + count))); do
1280				end=$((start + range_size))
1281				srcstart=$((start + src_delta))
1282				srcend=$((end + src_delta))
1283
1284				add "$(format)" 2>/dev/null
1285
1286				range_size=$((range_size + 1))
1287				start=$((end + range_size))
1288			done
1289
1290			nft flush inet filter test 2>/dev/null
1291
1292			range_size=1
1293			start=${cstart}
1294			for i in $(seq ${start} $((start + count))); do
1295				end=$((start + range_size))
1296				srcstart=$((start + src_delta))
1297				srcend=$((end + src_delta))
1298
1299				add "$(format)" 2>/dev/null
1300
1301				range_size=$((range_size + 1))
1302				start=$((end + range_size))
1303			done
1304
1305			nft flush ruleset
1306			setup set 2>/dev/null
1307
1308			range_size=1
1309			start=${cstart}
1310			for i in $(seq ${start} $((start + count))); do
1311				end=$((start + range_size))
1312				srcstart=$((start + src_delta))
1313				srcend=$((end + src_delta))
1314
1315				add "$(format)" 2>/dev/null
1316
1317				range_size=$((range_size + 1))
1318				start=$((end + range_size))
1319			done
1320
1321			range_size=1
1322			start=${cstart}
1323			for i in $(seq ${start} $((start + count))); do
1324				end=$((start + range_size))
1325				srcstart=$((start + src_delta))
1326				srcend=$((end + src_delta))
1327
1328				del "$(format)" 2>/dev/null
1329
1330				range_size=$((range_size + 1))
1331				start=$((end + range_size))
1332			done
1333		done
1334	) & pids="${pids} $!"
1335	done
1336
1337	# shellcheck disable=SC2046,SC2086 # word splitting wanted here
1338	wait $(for pid in ${pids}; do echo ${pid}; done)
1339	# shellcheck disable=SC2046,SC2086
1340	kill $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null
1341	# shellcheck disable=SC2046,SC2086
1342	wait $(for pid in ${flood_pids}; do echo ${pid}; done) 2>/dev/null
1343
1344	return 0
1345}
1346
1347# Timeout test template:
1348# - add all the elements with 3s timeout while checking that packets match
1349# - wait 3s after the last insertion, check that packets don't match any entry
1350test_timeout() {
1351	setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1352
1353	timeout=3
1354	range_size=1
1355	for i in $(seq "${start}" $((start + count))); do
1356		end=$((start + range_size))
1357		srcstart=$((start + src_delta))
1358		srcend=$((end + src_delta))
1359
1360		add "$(format)" || return 1
1361
1362		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1363			send_match "${j}" $((j + src_delta)) || return 1
1364		done
1365
1366		range_size=$((range_size + 1))
1367		start=$((end + range_size))
1368	done
1369	sleep 3
1370	for i in $(seq ${start} $((start + count))); do
1371		end=$((start + range_size))
1372		srcstart=$((start + src_delta))
1373		srcend=$((end + src_delta))
1374
1375		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1376			send_nomatch "${j}" $((j + src_delta)) || return 1
1377		done
1378
1379		range_size=$((range_size + 1))
1380		start=$((end + range_size))
1381	done
1382}
1383
1384# Performance test template:
1385# - add concatenated ranged entries
1386# - add non-ranged concatenated entries (for hash set matching rate baseline)
1387# - add ranged entries with first field only (for rbhash baseline)
1388# - start pktgen injection directly on device rx path of this namespace
1389# - measure drop only rate, hash and rbtree baselines, then matching rate
1390test_performance() {
1391	chain_spec=${perf_spec}
1392	dst="${perf_dst}"
1393	src="${perf_src}"
1394	setup veth perf set || return ${KSELFTEST_SKIP}
1395
1396	first=${start}
1397	range_size=1
1398	for set in test norange noconcat; do
1399		start=${first}
1400		for i in $(seq ${start} $((start + perf_entries))); do
1401			end=$((start + range_size))
1402			srcstart=$((start + src_delta))
1403			srcend=$((end + src_delta))
1404
1405			if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1406				start=${end}
1407				end=$((end + 1))
1408			elif [ ${start} -eq ${end} ]; then
1409				end=$((start + 1))
1410			fi
1411
1412			add_perf ${set}
1413
1414			start=$((end + range_size))
1415		done > "${tmp}"
1416		nft -f "${tmp}"
1417	done
1418
1419	perf $((end - 1)) ${srcstart}
1420
1421	sleep 2
1422
1423	nft add rule netdev perf test counter name \"test\" drop
1424	nft reset counter netdev perf test >/dev/null 2>&1
1425	sleep "${perf_duration}"
1426	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1427	info "    baseline (drop from netdev hook):            ${pps}pps"
1428	handle="$(nft -a list chain netdev perf test | grep counter)"
1429	handle="${handle##* }"
1430	nft delete rule netdev perf test handle "${handle}"
1431
1432	nft add rule "netdev perf test ${chain_spec} @norange \
1433		counter name \"test\" drop"
1434	nft reset counter netdev perf test >/dev/null 2>&1
1435	sleep "${perf_duration}"
1436	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1437	info "    baseline hash (non-ranged entries):          ${pps}pps"
1438	handle="$(nft -a list chain netdev perf test | grep counter)"
1439	handle="${handle##* }"
1440	nft delete rule netdev perf test handle "${handle}"
1441
1442	nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \
1443		counter name \"test\" drop"
1444	nft reset counter netdev perf test >/dev/null 2>&1
1445	sleep "${perf_duration}"
1446	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1447	info "    baseline rbtree (match on first field only): ${pps}pps"
1448	handle="$(nft -a list chain netdev perf test | grep counter)"
1449	handle="${handle##* }"
1450	nft delete rule netdev perf test handle "${handle}"
1451
1452	nft add rule "netdev perf test ${chain_spec} @test \
1453		counter name \"test\" drop"
1454	nft reset counter netdev perf test >/dev/null 2>&1
1455	sleep "${perf_duration}"
1456	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1457	p5="$(printf %5s "${perf_entries}")"
1458	info "    set with ${p5} full, ranged entries:         ${pps}pps"
1459	kill "${perf_pid}"
1460}
1461
1462test_bug_flush_remove_add() {
1463	set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
1464	elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
1465	elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
1466	for i in `seq 1 100`; do
1467		nft add table t ${set_cmd}	|| return ${KSELFTEST_SKIP}
1468		nft add element t s ${elem1}	2>/dev/null || return 1
1469		nft flush set t s		2>/dev/null || return 1
1470		nft add element t s ${elem2}	2>/dev/null || return 1
1471	done
1472	nft flush ruleset
1473}
1474
1475# - add ranged element, check that packets match it
1476# - reload the set, check packets still match
1477test_bug_reload() {
1478	setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1479	rstart=${start}
1480
1481	range_size=1
1482	for i in $(seq "${start}" $((start + count))); do
1483		end=$((start + range_size))
1484
1485		# Avoid negative or zero-sized port ranges
1486		if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1487			start=${end}
1488			end=$((end + 1))
1489		fi
1490		srcstart=$((start + src_delta))
1491		srcend=$((end + src_delta))
1492
1493		add "$(format)" || return 1
1494		range_size=$((range_size + 1))
1495		start=$((end + range_size))
1496	done
1497
1498	# check kernel does allocate pcpu sctrach map
1499	# for reload with no elemet add/delete
1500	( echo flush set inet filter test ;
1501	  nft list set inet filter test ) | nft -f -
1502
1503	start=${rstart}
1504	range_size=1
1505
1506	for i in $(seq "${start}" $((start + count))); do
1507		end=$((start + range_size))
1508
1509		# Avoid negative or zero-sized port ranges
1510		if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1511			start=${end}
1512			end=$((end + 1))
1513		fi
1514		srcstart=$((start + src_delta))
1515		srcend=$((end + src_delta))
1516
1517		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1518			send_match "${j}" $((j + src_delta)) || return 1
1519		done
1520
1521		range_size=$((range_size + 1))
1522		start=$((end + range_size))
1523	done
1524
1525	nft flush ruleset
1526}
1527
1528test_reported_issues() {
1529	eval test_bug_"${subtest}"
1530}
1531
1532# Run everything in a separate network namespace
1533[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
1534tmp="$(mktemp)"
1535trap cleanup EXIT
1536
1537# Entry point for test runs
1538passed=0
1539for name in ${TESTS}; do
1540	printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
1541	if [ "${name}" = "reported_issues" ]; then
1542		SUBTESTS="${BUGS}"
1543	else
1544		SUBTESTS="${TYPES}"
1545	fi
1546
1547	for subtest in ${SUBTESTS}; do
1548		eval desc=\$TYPE_"${subtest}"
1549		IFS='
1550'
1551		for __line in ${desc}; do
1552			# shellcheck disable=SC2086
1553			eval ${__line%%	*}=\"${__line##*	}\";
1554		done
1555		IFS='
1556'
1557
1558		if [ "${name}" = "concurrency" ] && \
1559		   [ "${race_repeat}" = "0" ]; then
1560			continue
1561		fi
1562		if [ "${name}" = "performance" ] && \
1563		   [ "${perf_duration}" = "0" ]; then
1564			continue
1565		fi
1566
1567		printf "  %-60s  " "${display}"
1568		eval test_"${name}"
1569		ret=$?
1570
1571		if [ $ret -eq 0 ]; then
1572			printf "[ OK ]\n"
1573			info_flush
1574			passed=$((passed + 1))
1575		elif [ $ret -eq 1 ]; then
1576			printf "[FAIL]\n"
1577			err_flush
1578			exit 1
1579		elif [ $ret -eq ${KSELFTEST_SKIP} ]; then
1580			printf "[SKIP]\n"
1581			err_flush
1582		fi
1583	done
1584done
1585
1586[ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} || exit 0
1587