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