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