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