1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3#
4# nft_concat_range.sh - Tests for sets with concatenation of ranged fields
5#
6# Copyright (c) 2019 Red Hat GmbH
7#
8# Author: Stefano Brivio <sbrivio@redhat.com>
9#
10# shellcheck disable=SC2154,SC2034,SC2016,SC2030,SC2031
11# ^ Configuration and templates sourced with eval, counters reused in subshells
12
13KSELFTEST_SKIP=4
14
15# Available test groups:
16# - reported_issues: check for issues that were reported in the past
17# - correctness: check that packets match given entries, and only those
18# - concurrency: attempt races between insertion, deletion and lookup
19# - timeout: check that packets match entries until they expire
20# - performance: estimate matching rate, compare with rbtree and hash baselines
21TESTS="reported_issues correctness concurrency timeout"
22[ "${quicktest}" != "1" ] && TESTS="${TESTS} performance"
23
24# Set types, defined by TYPE_ variables below
25TYPES="net_port port_net net6_port port_proto net6_port_mac net6_port_mac_proto
26       net_port_net net_mac 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 nc bash
70proto		udp
71
72race_repeat	3
73flood_tools	iperf3 iperf netperf
74flood_proto	udp
75flood_spec	ip daddr . udp dport
76
77perf_duration	5
78perf_spec	ip daddr . udp dport
79perf_dst	addr4 port
80perf_src
81perf_entries	1000
82perf_proto	ipv4
83"
84
85TYPE_port_net="
86display		port,net
87type_spec	inet_service . ipv4_addr
88chain_spec	udp dport . ip daddr
89dst		port addr4
90src
91start		1
92count		5
93src_delta	2000
94tools		sendip socat nc bash
95proto		udp
96
97race_repeat	3
98flood_tools	iperf3 iperf netperf
99flood_proto	udp
100flood_spec	udp dport . ip daddr
101
102perf_duration	5
103perf_spec	udp dport . ip daddr
104perf_dst	port addr4
105perf_src
106perf_entries	100
107perf_proto	ipv4
108"
109
110TYPE_net6_port="
111display		net6,port
112type_spec	ipv6_addr . inet_service
113chain_spec	ip6 daddr . udp dport
114dst		addr6 port
115src
116start		10
117count		5
118src_delta	2000
119tools		sendip socat nc bash
120proto		udp6
121
122race_repeat	3
123flood_tools	iperf3 iperf netperf
124flood_proto	tcp6
125flood_spec	ip6 daddr . udp dport
126
127perf_duration	5
128perf_spec	ip6 daddr . udp dport
129perf_dst	addr6 port
130perf_src
131perf_entries	1000
132perf_proto	ipv6
133"
134
135TYPE_port_proto="
136display		port,proto
137type_spec	inet_service . inet_proto
138chain_spec	udp dport . meta l4proto
139dst		port proto
140src
141start		1
142count		5
143src_delta	2000
144tools		sendip socat nc bash
145proto		udp
146
147race_repeat	0
148
149perf_duration	5
150perf_spec	udp dport . meta l4proto
151perf_dst	port proto
152perf_src
153perf_entries	30000
154perf_proto	ipv4
155"
156
157TYPE_net6_port_mac="
158display		net6,port,mac
159type_spec	ipv6_addr . inet_service . ether_addr
160chain_spec	ip6 daddr . udp dport . ether saddr
161dst		addr6 port
162src		mac
163start		10
164count		5
165src_delta	2000
166tools		sendip socat nc bash
167proto		udp6
168
169race_repeat	0
170
171perf_duration	5
172perf_spec	ip6 daddr . udp dport . ether daddr
173perf_dst	addr6 port mac
174perf_src
175perf_entries	10
176perf_proto	ipv6
177"
178
179TYPE_net6_port_mac_proto="
180display		net6,port,mac,proto
181type_spec	ipv6_addr . inet_service . ether_addr . inet_proto
182chain_spec	ip6 daddr . udp dport . ether saddr . meta l4proto
183dst		addr6 port
184src		mac proto
185start		10
186count		5
187src_delta	2000
188tools		sendip socat nc bash
189proto		udp6
190
191race_repeat	0
192
193perf_duration	5
194perf_spec	ip6 daddr . udp dport . ether daddr . meta l4proto
195perf_dst	addr6 port mac proto
196perf_src
197perf_entries	1000
198perf_proto	ipv6
199"
200
201TYPE_net_port_net="
202display		net,port,net
203type_spec	ipv4_addr . inet_service . ipv4_addr
204chain_spec	ip daddr . udp dport . ip saddr
205dst		addr4 port
206src		addr4
207start		1
208count		5
209src_delta	2000
210tools		sendip socat nc bash
211proto		udp
212
213race_repeat	3
214flood_tools	iperf3 iperf netperf
215flood_proto	tcp
216flood_spec	ip daddr . udp dport . ip saddr
217
218perf_duration	0
219"
220
221TYPE_net6_port_net6_port="
222display		net6,port,net6,port
223type_spec	ipv6_addr . inet_service . ipv6_addr . inet_service
224chain_spec	ip6 daddr . udp dport . ip6 saddr . udp sport
225dst		addr6 port
226src		addr6 port
227start		10
228count		5
229src_delta	2000
230tools		sendip socat nc
231proto		udp6
232
233race_repeat	3
234flood_tools	iperf3 iperf netperf
235flood_proto	tcp6
236flood_spec	ip6 daddr . tcp dport . ip6 saddr . tcp sport
237
238perf_duration	0
239"
240
241TYPE_net_port_mac_proto_net="
242display		net,port,mac,proto,net
243type_spec	ipv4_addr . inet_service . ether_addr . inet_proto . ipv4_addr
244chain_spec	ip daddr . udp dport . ether saddr . meta l4proto . ip saddr
245dst		addr4 port
246src		mac proto addr4
247start		1
248count		5
249src_delta	2000
250tools		sendip socat nc bash
251proto		udp
252
253race_repeat	0
254
255perf_duration	0
256"
257
258TYPE_net_mac="
259display		net,mac
260type_spec	ipv4_addr . ether_addr
261chain_spec	ip daddr . ether saddr
262dst		addr4
263src		mac
264start		1
265count		5
266src_delta	2000
267tools		sendip socat nc bash
268proto		udp
269
270race_repeat	0
271
272perf_duration	5
273perf_spec	ip daddr . ether daddr
274perf_dst	addr4 mac
275perf_src
276perf_entries	1000
277perf_proto	ipv4
278"
279
280TYPE_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 nc 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 nc
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 nc 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	sleep 2
478}
479
480# Fill in set template and initialise set
481setup_set() {
482	eval "echo \"${set_template}\"" | nft -f -
483}
484
485# Check that at least one of the needed tools is available
486check_tools() {
487	[ -z "${tools}" ] && return 0
488
489	__tools=
490	for tool in ${tools}; do
491		if [ "${tool}" = "nc" ] && [ "${proto}" = "udp6" ] && \
492		   ! nc -u -w0 1.1.1.1 1 2>/dev/null; then
493			# Some GNU netcat builds might not support IPv6
494			__tools="${__tools} netcat-openbsd"
495			continue
496		fi
497		__tools="${__tools} ${tool}"
498
499		command -v "${tool}" >/dev/null && return 0
500	done
501	err "need one of:${__tools}, skipping" && return 1
502}
503
504# Set up function to send ICMP packets
505setup_send_icmp() {
506	send_icmp() {
507		B ping -c1 -W1 "${dst_addr4}" >/dev/null 2>&1
508	}
509}
510
511# Set up function to send ICMPv6 packets
512setup_send_icmp6() {
513	if command -v ping6 >/dev/null; then
514		send_icmp6() {
515			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
516				2>/dev/null
517			B ping6 -q -c1 -W1 "${dst_addr6}"
518		}
519	else
520		send_icmp6() {
521			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
522				2>/dev/null
523			B ping -q -6 -c1 -W1 "${dst_addr6}"
524		}
525	fi
526}
527
528# Set up function to send single UDP packets on IPv4
529setup_send_udp() {
530	if command -v sendip >/dev/null; then
531		send_udp() {
532			[ -n "${src_port}" ] && src_port="-us ${src_port}"
533			[ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
534			[ -n "${src_addr4}" ] && src_addr4="-is ${src_addr4}"
535
536			# shellcheck disable=SC2086 # sendip needs split options
537			B sendip -p ipv4 -p udp ${src_addr4} ${src_port} \
538						${dst_port} "${dst_addr4}"
539
540			src_port=
541			dst_port=
542			src_addr4=
543		}
544	elif command -v socat -v >/dev/null; then
545		send_udp() {
546			if [ -n "${src_addr4}" ]; then
547				B ip addr add "${src_addr4}" dev veth_b
548				__socatbind=",bind=${src_addr4}"
549				if [ -n "${src_port}" ];then
550					__socatbind="${__socatbind}:${src_port}"
551				fi
552			fi
553
554			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
555			[ -z "${dst_port}" ] && dst_port=12345
556
557			echo "test4" | B socat -t 0.01 STDIN UDP4-DATAGRAM:${dst_addr4}:${dst_port}"${__socatbind}"
558
559			src_addr4=
560			src_port=
561		}
562	elif command -v nc >/dev/null; then
563		if nc -u -w0 1.1.1.1 1 2>/dev/null; then
564			# OpenBSD netcat
565			nc_opt="-w0"
566		else
567			# GNU netcat
568			nc_opt="-q0"
569		fi
570
571		send_udp() {
572			if [ -n "${src_addr4}" ]; then
573				B ip addr add "${src_addr4}" dev veth_b
574				__src_addr4="-s ${src_addr4}"
575			fi
576			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
577			[ -n "${src_port}" ] && src_port="-p ${src_port}"
578
579			echo "" | B nc -u "${nc_opt}" "${__src_addr4}" \
580				  "${src_port}" "${dst_addr4}" "${dst_port}"
581
582			src_addr4=
583			src_port=
584		}
585	elif [ -z "$(bash -c 'type -p')" ]; then
586		send_udp() {
587			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
588			if [ -n "${src_addr4}" ]; then
589				B ip addr add "${src_addr4}/16" dev veth_b
590				B ip route add default dev veth_b
591			fi
592
593			B bash -c "echo > /dev/udp/${dst_addr4}/${dst_port}"
594
595			if [ -n "${src_addr4}" ]; then
596				B ip addr del "${src_addr4}/16" dev veth_b
597			fi
598			src_addr4=
599		}
600	else
601		return 1
602	fi
603}
604
605# Set up function to send single UDP packets on IPv6
606setup_send_udp6() {
607	if command -v sendip >/dev/null; then
608		send_udp6() {
609			[ -n "${src_port}" ] && src_port="-us ${src_port}"
610			[ -n "${dst_port}" ] && dst_port="-ud ${dst_port}"
611			if [ -n "${src_addr6}" ]; then
612				src_addr6="-6s ${src_addr6}"
613			else
614				src_addr6="-6s 2001:db8::2"
615			fi
616			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
617				2>/dev/null
618
619			# shellcheck disable=SC2086 # this needs split options
620			B sendip -p ipv6 -p udp ${src_addr6} ${src_port} \
621						${dst_port} "${dst_addr6}"
622
623			src_port=
624			dst_port=
625			src_addr6=
626		}
627	elif command -v socat -v >/dev/null; then
628		send_udp6() {
629			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
630				2>/dev/null
631
632			__socatbind6=
633
634			if [ -n "${src_addr6}" ]; then
635				if [ -n "${src_addr6} != "${src_addr6_added} ]; then
636					B ip addr add "${src_addr6}" dev veth_b nodad
637
638					src_addr6_added=${src_addr6}
639				fi
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 command -v nc >/dev/null && nc -u -w0 1.1.1.1 1 2>/dev/null; then
651		# GNU netcat might not work with IPv6, try next tool
652		send_udp6() {
653			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
654				2>/dev/null
655			if [ -n "${src_addr6}" ]; then
656				B ip addr add "${src_addr6}" dev veth_b nodad
657			else
658				src_addr6="2001:db8::2"
659			fi
660			[ -n "${src_port}" ] && src_port="-p ${src_port}"
661
662			# shellcheck disable=SC2086 # this needs split options
663			echo "" | B nc -u w0 "-s${src_addr6}" ${src_port} \
664					       ${dst_addr6} ${dst_port}
665
666			src_addr6=
667			src_port=
668		}
669	elif [ -z "$(bash -c 'type -p')" ]; then
670		send_udp6() {
671			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
672				2>/dev/null
673			B ip addr add "${src_addr6}" dev veth_b nodad
674			B bash -c "echo > /dev/udp/${dst_addr6}/${dst_port}"
675			ip -6 addr del "${dst_addr6}" dev veth_a 2>/dev/null
676		}
677	else
678		return 1
679	fi
680}
681
682# Set up function to send TCP traffic on IPv4
683setup_flood_tcp() {
684	if command -v iperf3 >/dev/null; then
685		flood_tcp() {
686			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
687			if [ -n "${src_addr4}" ]; then
688				B ip addr add "${src_addr4}/16" dev veth_b
689				src_addr4="-B ${src_addr4}"
690			else
691				B ip addr add dev veth_b 10.0.0.2
692				src_addr4="-B 10.0.0.2"
693			fi
694			if [ -n "${src_port}" ]; then
695				src_port="--cport ${src_port}"
696			fi
697			B ip route add default dev veth_b 2>/dev/null
698			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
699
700			# shellcheck disable=SC2086 # this needs split options
701			iperf3 -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
702			sleep 2
703
704			# shellcheck disable=SC2086 # this needs split options
705			B iperf3 -c "${dst_addr4}" ${dst_port} ${src_port} \
706				${src_addr4} -l16 -t 1000
707
708			src_addr4=
709			src_port=
710			dst_port=
711		}
712	elif command -v iperf >/dev/null; then
713		flood_tcp() {
714			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
715			if [ -n "${src_addr4}" ]; then
716				B ip addr add "${src_addr4}/16" dev veth_b
717				src_addr4="-B ${src_addr4}"
718			else
719				B ip addr add dev veth_b 10.0.0.2 2>/dev/null
720				src_addr4="-B 10.0.0.2"
721			fi
722			if [ -n "${src_port}" ]; then
723				src_addr4="${src_addr4}:${src_port}"
724			fi
725			B ip route add default dev veth_b
726			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
727
728			# shellcheck disable=SC2086 # this needs split options
729			iperf -s -DB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
730			sleep 2
731
732			# shellcheck disable=SC2086 # this needs split options
733			B iperf -c "${dst_addr4}" ${dst_port} ${src_addr4} \
734				-l20 -t 1000
735
736			src_addr4=
737			src_port=
738			dst_port=
739		}
740	elif command -v netperf >/dev/null; then
741		flood_tcp() {
742			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
743			if [ -n "${src_addr4}" ]; then
744				B ip addr add "${src_addr4}/16" dev veth_b
745			else
746				B ip addr add dev veth_b 10.0.0.2
747				src_addr4="10.0.0.2"
748			fi
749			if [ -n "${src_port}" ]; then
750				dst_port="${dst_port},${src_port}"
751			fi
752			B ip route add default dev veth_b
753			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
754
755			# shellcheck disable=SC2086 # this needs split options
756			netserver -4 ${dst_port} -L "${dst_addr4}" \
757				>/dev/null 2>&1
758			sleep 2
759
760			# shellcheck disable=SC2086 # this needs split options
761			B netperf -4 -H "${dst_addr4}" ${dst_port} \
762				-L "${src_addr4}" -l 1000 -t TCP_STREAM
763
764			src_addr4=
765			src_port=
766			dst_port=
767		}
768	else
769		return 1
770	fi
771}
772
773# Set up function to send TCP traffic on IPv6
774setup_flood_tcp6() {
775	if command -v iperf3 >/dev/null; then
776		flood_tcp6() {
777			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
778			if [ -n "${src_addr6}" ]; then
779				B ip addr add "${src_addr6}" dev veth_b nodad
780				src_addr6="-B ${src_addr6}"
781			else
782				src_addr6="-B 2001:db8::2"
783			fi
784			if [ -n "${src_port}" ]; then
785				src_port="--cport ${src_port}"
786			fi
787			B ip route add default dev veth_b
788			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
789				2>/dev/null
790
791			# shellcheck disable=SC2086 # this needs split options
792			iperf3 -s -DB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
793			sleep 2
794
795			# shellcheck disable=SC2086 # this needs split options
796			B iperf3 -c "${dst_addr6}" ${dst_port} \
797				${src_port} ${src_addr6} -l16 -t 1000
798
799			src_addr6=
800			src_port=
801			dst_port=
802		}
803	elif command -v iperf >/dev/null; then
804		flood_tcp6() {
805			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
806			if [ -n "${src_addr6}" ]; then
807				B ip addr add "${src_addr6}" dev veth_b nodad
808				src_addr6="-B ${src_addr6}"
809			else
810				src_addr6="-B 2001:db8::2"
811			fi
812			if [ -n "${src_port}" ]; then
813				src_addr6="${src_addr6}:${src_port}"
814			fi
815			B ip route add default dev veth_b
816			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
817				2>/dev/null
818
819			# shellcheck disable=SC2086 # this needs split options
820			iperf -s -VDB "${dst_addr6}" ${dst_port} >/dev/null 2>&1
821			sleep 2
822
823			# shellcheck disable=SC2086 # this needs split options
824			B iperf -c "${dst_addr6}" -V ${dst_port} \
825				${src_addr6} -l1 -t 1000
826
827			src_addr6=
828			src_port=
829			dst_port=
830		}
831	elif command -v netperf >/dev/null; then
832		flood_tcp6() {
833			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
834			if [ -n "${src_addr6}" ]; then
835				B ip addr add "${src_addr6}" dev veth_b nodad
836			else
837				src_addr6="2001:db8::2"
838			fi
839			if [ -n "${src_port}" ]; then
840				dst_port="${dst_port},${src_port}"
841			fi
842			B ip route add default dev veth_b
843			ip -6 addr add "${dst_addr6}" dev veth_a nodad \
844				2>/dev/null
845
846			# shellcheck disable=SC2086 # this needs split options
847			netserver -6 ${dst_port} -L "${dst_addr6}" \
848				>/dev/null 2>&1
849			sleep 2
850
851			# shellcheck disable=SC2086 # this needs split options
852			B netperf -6 -H "${dst_addr6}" ${dst_port} \
853				-L "${src_addr6}" -l 1000 -t TCP_STREAM
854
855			src_addr6=
856			src_port=
857			dst_port=
858		}
859	else
860		return 1
861	fi
862}
863
864# Set up function to send UDP traffic on IPv4
865setup_flood_udp() {
866	if command -v iperf3 >/dev/null; then
867		flood_udp() {
868			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
869			if [ -n "${src_addr4}" ]; then
870				B ip addr add "${src_addr4}/16" dev veth_b
871				src_addr4="-B ${src_addr4}"
872			else
873				B ip addr add dev veth_b 10.0.0.2 2>/dev/null
874				src_addr4="-B 10.0.0.2"
875			fi
876			if [ -n "${src_port}" ]; then
877				src_port="--cport ${src_port}"
878			fi
879			B ip route add default dev veth_b
880			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
881
882			# shellcheck disable=SC2086 # this needs split options
883			iperf3 -s -DB "${dst_addr4}" ${dst_port}
884			sleep 2
885
886			# shellcheck disable=SC2086 # this needs split options
887			B iperf3 -u -c "${dst_addr4}" -Z -b 100M -l16 -t1000 \
888				${dst_port} ${src_port} ${src_addr4}
889
890			src_addr4=
891			src_port=
892			dst_port=
893		}
894	elif command -v iperf >/dev/null; then
895		flood_udp() {
896			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
897			if [ -n "${src_addr4}" ]; then
898				B ip addr add "${src_addr4}/16" dev veth_b
899				src_addr4="-B ${src_addr4}"
900			else
901				B ip addr add dev veth_b 10.0.0.2
902				src_addr4="-B 10.0.0.2"
903			fi
904			if [ -n "${src_port}" ]; then
905				src_addr4="${src_addr4}:${src_port}"
906			fi
907			B ip route add default dev veth_b
908			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
909
910			# shellcheck disable=SC2086 # this needs split options
911			iperf -u -sDB "${dst_addr4}" ${dst_port} >/dev/null 2>&1
912			sleep 2
913
914			# shellcheck disable=SC2086 # this needs split options
915			B iperf -u -c "${dst_addr4}" -b 100M -l1 -t1000 \
916				${dst_port} ${src_addr4}
917
918			src_addr4=
919			src_port=
920			dst_port=
921		}
922	elif command -v netperf >/dev/null; then
923		flood_udp() {
924			[ -n "${dst_port}" ] && dst_port="-p ${dst_port}"
925			if [ -n "${src_addr4}" ]; then
926				B ip addr add "${src_addr4}/16" dev veth_b
927			else
928				B ip addr add dev veth_b 10.0.0.2
929				src_addr4="10.0.0.2"
930			fi
931			if [ -n "${src_port}" ]; then
932				dst_port="${dst_port},${src_port}"
933			fi
934			B ip route add default dev veth_b
935			ip addr add "${dst_addr4}" dev veth_a 2>/dev/null
936
937			# shellcheck disable=SC2086 # this needs split options
938			netserver -4 ${dst_port} -L "${dst_addr4}" \
939				>/dev/null 2>&1
940			sleep 2
941
942			# shellcheck disable=SC2086 # this needs split options
943			B netperf -4 -H "${dst_addr4}" ${dst_port} \
944				-L "${src_addr4}" -l 1000 -t UDP_STREAM
945
946			src_addr4=
947			src_port=
948			dst_port=
949		}
950	else
951		return 1
952	fi
953}
954
955# Find pktgen script and set up function to start pktgen injection
956setup_perf() {
957	for pktgen_script_path in ${PKTGEN_SCRIPT_PATHS} __notfound; do
958		command -v "${pktgen_script_path}" >/dev/null && break
959	done
960	[ "${pktgen_script_path}" = "__notfound" ] && return 1
961
962	perf_ipv4() {
963		${pktgen_script_path} -s80 \
964			-i veth_a -d "${dst_addr4}" -p "${dst_port}" \
965			-m "${dst_mac}" \
966			-t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
967		perf_pid=$!
968	}
969	perf_ipv6() {
970		IP6=6 ${pktgen_script_path} -s100 \
971			-i veth_a -d "${dst_addr6}" -p "${dst_port}" \
972			-m "${dst_mac}" \
973			-t $(($(nproc) / 5 + 1)) -b10000 -n0 2>/dev/null &
974		perf_pid=$!
975	}
976}
977
978# Clean up before each test
979cleanup() {
980	nft reset counter inet filter test	>/dev/null 2>&1
981	nft flush ruleset			>/dev/null 2>&1
982	ip link del dummy0			2>/dev/null
983	ip route del default			2>/dev/null
984	ip -6 route del default			2>/dev/null
985	ip netns del B				2>/dev/null
986	ip link del veth_a			2>/dev/null
987	timeout=
988	killall iperf3				2>/dev/null
989	killall iperf				2>/dev/null
990	killall netperf				2>/dev/null
991	killall netserver			2>/dev/null
992	rm -f ${tmp}
993	sleep 2
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 ${KSELFTEST_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 ${KSELFTEST_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 ${KSELFTEST_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 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 ${KSELFTEST_SKIP}
1411
1412	timeout=3
1413	range_size=1
1414	for i in $(seq "${start}" $((start + count))); do
1415		end=$((start + range_size))
1416		srcstart=$((start + src_delta))
1417		srcend=$((end + src_delta))
1418
1419		add "$(format)" || return 1
1420
1421		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1422			send_match "${j}" $((j + src_delta)) || return 1
1423		done
1424
1425		range_size=$((range_size + 1))
1426		start=$((end + range_size))
1427	done
1428	sleep 3
1429	for i in $(seq ${start} $((start + count))); do
1430		end=$((start + range_size))
1431		srcstart=$((start + src_delta))
1432		srcend=$((end + src_delta))
1433
1434		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1435			send_nomatch "${j}" $((j + src_delta)) || return 1
1436		done
1437
1438		range_size=$((range_size + 1))
1439		start=$((end + range_size))
1440	done
1441}
1442
1443# Performance test template:
1444# - add concatenated ranged entries
1445# - add non-ranged concatenated entries (for hash set matching rate baseline)
1446# - add ranged entries with first field only (for rbhash baseline)
1447# - start pktgen injection directly on device rx path of this namespace
1448# - measure drop only rate, hash and rbtree baselines, then matching rate
1449test_performance() {
1450	chain_spec=${perf_spec}
1451	dst="${perf_dst}"
1452	src="${perf_src}"
1453	setup veth perf set || return ${KSELFTEST_SKIP}
1454
1455	first=${start}
1456	range_size=1
1457	for set in test norange noconcat; do
1458		start=${first}
1459		for i in $(seq ${start} $((start + perf_entries))); do
1460			end=$((start + range_size))
1461			srcstart=$((start + src_delta))
1462			srcend=$((end + src_delta))
1463
1464			if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1465				start=${end}
1466				end=$((end + 1))
1467			elif [ ${start} -eq ${end} ]; then
1468				end=$((start + 1))
1469			fi
1470
1471			add_perf ${set}
1472
1473			start=$((end + range_size))
1474		done > "${tmp}"
1475		nft -f "${tmp}"
1476	done
1477
1478	perf $((end - 1)) ${srcstart}
1479
1480	sleep 2
1481
1482	nft add rule netdev perf test counter name \"test\" drop
1483	nft reset counter netdev perf test >/dev/null 2>&1
1484	sleep "${perf_duration}"
1485	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1486	info "    baseline (drop from netdev hook):            ${pps}pps"
1487	handle="$(nft -a list chain netdev perf test | grep counter)"
1488	handle="${handle##* }"
1489	nft delete rule netdev perf test handle "${handle}"
1490
1491	nft add rule "netdev perf test ${chain_spec} @norange \
1492		counter name \"test\" drop"
1493	nft reset counter netdev perf test >/dev/null 2>&1
1494	sleep "${perf_duration}"
1495	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1496	info "    baseline hash (non-ranged entries):          ${pps}pps"
1497	handle="$(nft -a list chain netdev perf test | grep counter)"
1498	handle="${handle##* }"
1499	nft delete rule netdev perf test handle "${handle}"
1500
1501	nft add rule "netdev perf test ${chain_spec%%. *} @noconcat \
1502		counter name \"test\" drop"
1503	nft reset counter netdev perf test >/dev/null 2>&1
1504	sleep "${perf_duration}"
1505	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1506	info "    baseline rbtree (match on first field only): ${pps}pps"
1507	handle="$(nft -a list chain netdev perf test | grep counter)"
1508	handle="${handle##* }"
1509	nft delete rule netdev perf test handle "${handle}"
1510
1511	nft add rule "netdev perf test ${chain_spec} @test \
1512		counter name \"test\" drop"
1513	nft reset counter netdev perf test >/dev/null 2>&1
1514	sleep "${perf_duration}"
1515	pps="$(printf %10s $(($(count_perf_packets) / perf_duration)))"
1516	p5="$(printf %5s "${perf_entries}")"
1517	info "    set with ${p5} full, ranged entries:         ${pps}pps"
1518	kill "${perf_pid}"
1519}
1520
1521test_bug_flush_remove_add() {
1522	set_cmd='{ set s { type ipv4_addr . inet_service; flags interval; }; }'
1523	elem1='{ 10.0.0.1 . 22-25, 10.0.0.1 . 10-20 }'
1524	elem2='{ 10.0.0.1 . 10-20, 10.0.0.1 . 22-25 }'
1525	for i in `seq 1 100`; do
1526		nft add table t ${set_cmd}	|| return ${KSELFTEST_SKIP}
1527		nft add element t s ${elem1}	2>/dev/null || return 1
1528		nft flush set t s		2>/dev/null || return 1
1529		nft add element t s ${elem2}	2>/dev/null || return 1
1530	done
1531	nft flush ruleset
1532}
1533
1534# - add ranged element, check that packets match it
1535# - reload the set, check packets still match
1536test_bug_reload() {
1537	setup veth send_"${proto}" set || return ${KSELFTEST_SKIP}
1538	rstart=${start}
1539
1540	range_size=1
1541	for i in $(seq "${start}" $((start + count))); do
1542		end=$((start + range_size))
1543
1544		# Avoid negative or zero-sized port ranges
1545		if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1546			start=${end}
1547			end=$((end + 1))
1548		fi
1549		srcstart=$((start + src_delta))
1550		srcend=$((end + src_delta))
1551
1552		add "$(format)" || return 1
1553		range_size=$((range_size + 1))
1554		start=$((end + range_size))
1555	done
1556
1557	# check kernel does allocate pcpu sctrach map
1558	# for reload with no elemet add/delete
1559	( echo flush set inet filter test ;
1560	  nft list set inet filter test ) | nft -f -
1561
1562	start=${rstart}
1563	range_size=1
1564
1565	for i in $(seq "${start}" $((start + count))); do
1566		end=$((start + range_size))
1567
1568		# Avoid negative or zero-sized port ranges
1569		if [ $((end / 65534)) -gt $((start / 65534)) ]; then
1570			start=${end}
1571			end=$((end + 1))
1572		fi
1573		srcstart=$((start + src_delta))
1574		srcend=$((end + src_delta))
1575
1576		for j in $(seq ${start} $((range_size / 2 + 1)) ${end}); do
1577			send_match "${j}" $((j + src_delta)) || return 1
1578		done
1579
1580		range_size=$((range_size + 1))
1581		start=$((end + range_size))
1582	done
1583
1584	nft flush ruleset
1585}
1586
1587test_reported_issues() {
1588	eval test_bug_"${subtest}"
1589}
1590
1591# Run everything in a separate network namespace
1592[ "${1}" != "run" ] && { unshare -n "${0}" run; exit $?; }
1593tmp="$(mktemp)"
1594trap cleanup EXIT
1595
1596# Entry point for test runs
1597passed=0
1598for name in ${TESTS}; do
1599	printf "TEST: %s\n" "$(echo ${name} | tr '_' ' ')"
1600	if [ "${name}" = "reported_issues" ]; then
1601		SUBTESTS="${BUGS}"
1602	else
1603		SUBTESTS="${TYPES}"
1604	fi
1605
1606	for subtest in ${SUBTESTS}; do
1607		eval desc=\$TYPE_"${subtest}"
1608		IFS='
1609'
1610		for __line in ${desc}; do
1611			# shellcheck disable=SC2086
1612			eval ${__line%%	*}=\"${__line##*	}\";
1613		done
1614		IFS='
1615'
1616
1617		if [ "${name}" = "concurrency" ] && \
1618		   [ "${race_repeat}" = "0" ]; then
1619			continue
1620		fi
1621		if [ "${name}" = "performance" ] && \
1622		   [ "${perf_duration}" = "0" ]; then
1623			continue
1624		fi
1625
1626		printf "  %-60s  " "${display}"
1627		eval test_"${name}"
1628		ret=$?
1629
1630		if [ $ret -eq 0 ]; then
1631			printf "[ OK ]\n"
1632			info_flush
1633			passed=$((passed + 1))
1634		elif [ $ret -eq 1 ]; then
1635			printf "[FAIL]\n"
1636			err_flush
1637			exit 1
1638		elif [ $ret -eq ${KSELFTEST_SKIP} ]; then
1639			printf "[SKIP]\n"
1640			err_flush
1641		fi
1642	done
1643done
1644
1645[ ${passed} -eq 0 ] && exit ${KSELFTEST_SKIP} || exit 0
1646