1#!/bin/bash
2
3# Test insertion speed for packets with identical addresses/ports
4# that are all placed in distinct conntrack zones.
5
6sfx=$(mktemp -u "XXXXXXXX")
7ns="ns-$sfx"
8
9# Kselftest framework requirement - SKIP code is 4.
10ksft_skip=4
11
12zones=20000
13have_ct_tool=0
14ret=0
15
16cleanup()
17{
18	ip netns del $ns
19}
20
21checktool (){
22	if ! $1 > /dev/null 2>&1; then
23		echo "SKIP: Could not $2"
24		exit $ksft_skip
25	fi
26}
27
28checktool "nft --version" "run test without nft tool"
29checktool "ip -Version" "run test without ip tool"
30checktool "socat -V" "run test without socat tool"
31checktool "ip netns add $ns" "create net namespace"
32
33trap cleanup EXIT
34
35conntrack -V > /dev/null 2>&1
36if [ $? -eq 0 ];then
37	have_ct_tool=1
38fi
39
40ip -net "$ns" link set lo up
41
42test_zones() {
43	local max_zones=$1
44
45ip netns exec $ns sysctl -q net.netfilter.nf_conntrack_udp_timeout=3600
46ip netns exec $ns nft -f /dev/stdin<<EOF
47flush ruleset
48table inet raw {
49	map rndzone {
50		typeof numgen inc mod $max_zones : ct zone
51	}
52
53	chain output {
54		type filter hook output priority -64000; policy accept;
55		udp dport 12345  ct zone set numgen inc mod 65536 map @rndzone
56	}
57}
58EOF
59	(
60		echo "add element inet raw rndzone {"
61	for i in $(seq 1 $max_zones);do
62		echo -n "$i : $i"
63		if [ $i -lt $max_zones ]; then
64			echo ","
65		else
66			echo "}"
67		fi
68	done
69	) | ip netns exec $ns nft -f /dev/stdin
70
71	local i=0
72	local j=0
73	local outerstart=$(date +%s%3N)
74	local stop=$outerstart
75
76	while [ $i -lt $max_zones ]; do
77		local start=$(date +%s%3N)
78		i=$((i + 10000))
79		j=$((j + 1))
80		# nft rule in output places each packet in a different zone.
81		dd if=/dev/zero of=/dev/stdout bs=8k count=10000 2>/dev/null | ip netns exec "$ns" socat STDIN UDP:127.0.0.1:12345,sourceport=12345
82		if [ $? -ne 0 ] ;then
83			ret=1
84			break
85		fi
86
87		stop=$(date +%s%3N)
88		local duration=$((stop-start))
89		echo "PASS: added 10000 entries in $duration ms (now $i total, loop $j)"
90	done
91
92	if [ $have_ct_tool -eq 1 ]; then
93		local count=$(ip netns exec "$ns" conntrack -C)
94		local duration=$((stop-outerstart))
95
96		if [ $count -eq $max_zones ]; then
97			echo "PASS: inserted $count entries from packet path in $duration ms total"
98		else
99			ip netns exec $ns conntrack -S 1>&2
100			echo "FAIL: inserted $count entries from packet path in $duration ms total, expected $max_zones entries"
101			ret=1
102		fi
103	fi
104
105	if [ $ret -ne 0 ];then
106		echo "FAIL: insert $max_zones entries from packet path" 1>&2
107	fi
108}
109
110test_conntrack_tool() {
111	local max_zones=$1
112
113	ip netns exec $ns conntrack -F >/dev/null 2>/dev/null
114
115	local outerstart=$(date +%s%3N)
116	local start=$(date +%s%3N)
117	local stop=$start
118	local i=0
119	while [ $i -lt $max_zones ]; do
120		i=$((i + 1))
121		ip netns exec "$ns" conntrack -I -s 1.1.1.1 -d 2.2.2.2 --protonum 6 \
122	                 --timeout 3600 --state ESTABLISHED --sport 12345 --dport 1000 --zone $i >/dev/null 2>&1
123		if [ $? -ne 0 ];then
124			ip netns exec "$ns" conntrack -I -s 1.1.1.1 -d 2.2.2.2 --protonum 6 \
125	                 --timeout 3600 --state ESTABLISHED --sport 12345 --dport 1000 --zone $i > /dev/null
126			echo "FAIL: conntrack -I returned an error"
127			ret=1
128			break
129		fi
130
131		if [ $((i%10000)) -eq 0 ];then
132			stop=$(date +%s%3N)
133
134			local duration=$((stop-start))
135			echo "PASS: added 10000 entries in $duration ms (now $i total)"
136			start=$stop
137		fi
138	done
139
140	local count=$(ip netns exec "$ns" conntrack -C)
141	local duration=$((stop-outerstart))
142
143	if [ $count -eq $max_zones ]; then
144		echo "PASS: inserted $count entries via ctnetlink in $duration ms"
145	else
146		ip netns exec $ns conntrack -S 1>&2
147		echo "FAIL: inserted $count entries via ctnetlink in $duration ms, expected $max_zones entries ($duration ms)"
148		ret=1
149	fi
150}
151
152test_zones $zones
153
154if [ $have_ct_tool -eq 1 ];then
155	test_conntrack_tool $zones
156else
157	echo "SKIP: Could not run ctnetlink insertion test without conntrack tool"
158	if [ $ret -eq 0 ];then
159		exit $ksft_skip
160	fi
161fi
162
163exit $ret
164