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