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