1#!/bin/bash
2#
3# This test is for stress-testing the nf_tables config plane path vs.
4# packet path processing: Make sure we never release rules that are
5# still visible to other cpus.
6#
7# set -e
8
9# Kselftest framework requirement - SKIP code is 4.
10ksft_skip=4
11
12testns=testns-$(mktemp -u "XXXXXXXX")
13
14tables="foo bar baz quux"
15global_ret=0
16eret=0
17lret=0
18
19check_result()
20{
21	local r=$1
22	local OK="PASS"
23
24	if [ $r -ne 0 ] ;then
25		OK="FAIL"
26		global_ret=$r
27	fi
28
29	echo "$OK: nft $2 test returned $r"
30
31	eret=0
32}
33
34nft --version > /dev/null 2>&1
35if [ $? -ne 0 ];then
36	echo "SKIP: Could not run test without nft tool"
37	exit $ksft_skip
38fi
39
40ip -Version > /dev/null 2>&1
41if [ $? -ne 0 ];then
42	echo "SKIP: Could not run test without ip tool"
43	exit $ksft_skip
44fi
45
46tmp=$(mktemp)
47
48for table in $tables; do
49	echo add table inet "$table" >> "$tmp"
50	echo flush table inet "$table" >> "$tmp"
51
52	echo "add chain inet $table INPUT { type filter hook input priority 0; }" >> "$tmp"
53	echo "add chain inet $table OUTPUT { type filter hook output priority 0; }" >> "$tmp"
54	for c in $(seq 1 400); do
55		chain=$(printf "chain%03u" "$c")
56		echo "add chain inet $table $chain" >> "$tmp"
57	done
58
59	for c in $(seq 1 400); do
60		chain=$(printf "chain%03u" "$c")
61		for BASE in INPUT OUTPUT; do
62			echo "add rule inet $table $BASE counter jump $chain" >> "$tmp"
63		done
64		echo "add rule inet $table $chain counter return" >> "$tmp"
65	done
66done
67
68ip netns add "$testns"
69ip -netns "$testns" link set lo up
70
71lscpu | grep ^CPU\(s\): | ( read cpu cpunum ;
72cpunum=$((cpunum-1))
73for i in $(seq 0 $cpunum);do
74	mask=$(printf 0x%x $((1<<$i)))
75        ip netns exec "$testns" taskset $mask ping -4 127.0.0.1 -fq > /dev/null &
76        ip netns exec "$testns" taskset $mask ping -6 ::1 -fq > /dev/null &
77done)
78
79sleep 1
80
81ip netns exec "$testns" nft -f "$tmp"
82for i in $(seq 1 10) ; do ip netns exec "$testns" nft -f "$tmp" & done
83
84for table in $tables;do
85	randsleep=$((RANDOM%2))
86	sleep $randsleep
87	ip netns exec "$testns" nft delete table inet $table
88	lret=$?
89	if [ $lret -ne 0 ]; then
90		eret=$lret
91	fi
92done
93
94check_result $eret "add/delete"
95
96for i in $(seq 1 10) ; do
97	(echo "flush ruleset"; cat "$tmp") | ip netns exec "$testns" nft -f /dev/stdin
98
99	lret=$?
100	if [ $lret -ne 0 ]; then
101		eret=$lret
102	fi
103done
104
105check_result $eret "reload"
106
107for i in $(seq 1 10) ; do
108	(echo "flush ruleset"; cat "$tmp"
109	 echo "insert rule inet foo INPUT meta nftrace set 1"
110	 echo "insert rule inet foo OUTPUT meta nftrace set 1"
111	 ) | ip netns exec "$testns" nft -f /dev/stdin
112	lret=$?
113	if [ $lret -ne 0 ]; then
114		eret=$lret
115	fi
116
117	(echo "flush ruleset"; cat "$tmp"
118	 ) | ip netns exec "$testns" nft -f /dev/stdin
119
120	lret=$?
121	if [ $lret -ne 0 ]; then
122		eret=$lret
123	fi
124done
125
126check_result $eret "add/delete with nftrace enabled"
127
128echo "insert rule inet foo INPUT meta nftrace set 1" >> $tmp
129echo "insert rule inet foo OUTPUT meta nftrace set 1" >> $tmp
130
131for i in $(seq 1 10) ; do
132	(echo "flush ruleset"; cat "$tmp") | ip netns exec "$testns" nft -f /dev/stdin
133
134	lret=$?
135	if [ $lret -ne 0 ]; then
136		eret=1
137	fi
138done
139
140check_result $lret "add/delete with nftrace enabled"
141
142pkill -9 ping
143
144wait
145
146rm -f "$tmp"
147ip netns del "$testns"
148
149exit $global_ret
150