1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3
4readonly STATS="$(mktemp -p /tmp ns-XXXXXX)"
5readonly BASE=`basename $STATS`
6readonly SRC=2
7readonly DST=1
8readonly DST_NAT=100
9readonly NS_SRC=$BASE$SRC
10readonly NS_DST=$BASE$DST
11
12# "baremetal" network used for raw UDP traffic
13readonly BM_NET_V4=192.168.1.
14readonly BM_NET_V6=2001:db8::
15
16readonly CPUS=`nproc`
17ret=0
18
19cleanup() {
20	local ns
21	local jobs
22	readonly jobs="$(jobs -p)"
23	[ -n "${jobs}" ] && kill -1 ${jobs} 2>/dev/null
24	rm -f $STATS
25
26	for ns in $NS_SRC $NS_DST; do
27		ip netns del $ns 2>/dev/null
28	done
29}
30
31trap cleanup EXIT
32
33create_ns() {
34	local ns
35
36	for ns in $NS_SRC $NS_DST; do
37		ip netns add $ns
38		ip -n $ns link set dev lo up
39	done
40
41	ip link add name veth$SRC type veth peer name veth$DST
42
43	for ns in $SRC $DST; do
44		ip link set dev veth$ns netns $BASE$ns up
45		ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
46		ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
47	done
48	echo "#kernel" > $BASE
49	chmod go-rw $BASE
50}
51
52__chk_flag() {
53	local msg="$1"
54	local target=$2
55	local expected=$3
56	local flagname=$4
57
58	local flag=`ip netns exec $BASE$target ethtool -k veth$target |\
59		    grep $flagname | awk '{print $2}'`
60
61	printf "%-60s" "$msg"
62	if [ "$flag" = "$expected" ]; then
63		echo " ok "
64	else
65		echo " fail - expected $expected found $flag"
66		ret=1
67	fi
68}
69
70chk_gro_flag() {
71	__chk_flag "$1" $2 $3 generic-receive-offload
72}
73
74chk_tso_flag() {
75	__chk_flag "$1" $2 $3 tcp-segmentation-offload
76}
77
78chk_channels() {
79	local msg="$1"
80	local target=$2
81	local rx=$3
82	local tx=$4
83
84	local dev=veth$target
85
86	local cur_rx=`ip netns exec $BASE$target ethtool -l $dev |\
87		grep RX: | tail -n 1 | awk '{print $2}' `
88		local cur_tx=`ip netns exec $BASE$target ethtool -l $dev |\
89		grep TX: | tail -n 1 | awk '{print $2}'`
90	local cur_combined=`ip netns exec $BASE$target ethtool -l $dev |\
91		grep Combined: | tail -n 1 | awk '{print $2}'`
92
93	printf "%-60s" "$msg"
94	if [ "$cur_rx" = "$rx" -a "$cur_tx" = "$tx" -a "$cur_combined" = "n/a" ]; then
95		echo " ok "
96	else
97		echo " fail rx:$rx:$cur_rx tx:$tx:$cur_tx combined:n/a:$cur_combined"
98	fi
99}
100
101chk_gro() {
102	local msg="$1"
103	local expected=$2
104
105	ip netns exec $BASE$SRC ping -qc 1 $BM_NET_V4$DST >/dev/null
106	NSTAT_HISTORY=$STATS ip netns exec $NS_DST nstat -n
107
108	printf "%-60s" "$msg"
109	ip netns exec $BASE$DST ./udpgso_bench_rx -C 1000 -R 10 &
110	local spid=$!
111	sleep 0.1
112
113	ip netns exec $NS_SRC ./udpgso_bench_tx -4 -s 13000 -S 1300 -M 1 -D $BM_NET_V4$DST
114	local retc=$?
115	wait $spid
116	local rets=$?
117	if [ ${rets} -ne 0 ] || [ ${retc} -ne 0 ]; then
118		echo " fail client exit code $retc, server $rets"
119		ret=1
120		return
121	fi
122
123	local pkts=`NSTAT_HISTORY=$STATS ip netns exec $NS_DST nstat IpInReceives | \
124		    awk '{print $2}' | tail -n 1`
125	if [ "$pkts" = "$expected" ]; then
126		echo " ok "
127	else
128		echo " fail - got $pkts packets, expected $expected "
129		ret=1
130	fi
131}
132
133__change_channels()
134{
135	local cur_cpu
136	local end=$1
137	local cur
138	local i
139
140	while true; do
141		printf -v cur '%(%s)T'
142		[ $cur -le $end ] || break
143
144		for i in `seq 1 $CPUS`; do
145			ip netns exec $NS_SRC ethtool -L veth$SRC rx $i tx $i
146			ip netns exec $NS_DST ethtool -L veth$DST rx $i tx $i
147		done
148
149		for i in `seq 1 $((CPUS - 1))`; do
150			cur_cpu=$((CPUS - $i))
151			ip netns exec $NS_SRC ethtool -L veth$SRC rx $cur_cpu tx $cur_cpu
152			ip netns exec $NS_DST ethtool -L veth$DST rx $cur_cpu tx $cur_cpu
153		done
154	done
155}
156
157__send_data() {
158	local end=$1
159
160	while true; do
161		printf -v cur '%(%s)T'
162		[ $cur -le $end ] || break
163
164		ip netns exec $NS_SRC ./udpgso_bench_tx -4 -s 1000 -M 300 -D $BM_NET_V4$DST
165	done
166}
167
168do_stress() {
169	local end
170	printf -v end '%(%s)T'
171	end=$((end + $STRESS))
172
173	ip netns exec $NS_SRC ethtool -L veth$SRC rx 3 tx 3
174	ip netns exec $NS_DST ethtool -L veth$DST rx 3 tx 3
175
176	ip netns exec $NS_DST ./udpgso_bench_rx &
177	local rx_pid=$!
178
179	echo "Running stress test for $STRESS seconds..."
180	__change_channels $end &
181	local ch_pid=$!
182	__send_data $end &
183	local data_pid_1=$!
184	__send_data $end &
185	local data_pid_2=$!
186	__send_data $end &
187	local data_pid_3=$!
188	__send_data $end &
189	local data_pid_4=$!
190
191	wait $ch_pid $data_pid_1 $data_pid_2 $data_pid_3 $data_pid_4
192	kill -9 $rx_pid
193	echo "done"
194
195	# restore previous setting
196	ip netns exec $NS_SRC ethtool -L veth$SRC rx 2 tx 2
197	ip netns exec $NS_DST ethtool -L veth$DST rx 2 tx 1
198}
199
200usage() {
201	echo "Usage: $0 [-h] [-s <seconds>]"
202	echo -e "\t-h: show this help"
203	echo -e "\t-s: run optional stress tests for the given amount of seconds"
204}
205
206STRESS=0
207while getopts "hs:" option; do
208	case "$option" in
209	"h")
210		usage $0
211		exit 0
212		;;
213	"s")
214		STRESS=$OPTARG
215		;;
216	esac
217done
218
219if [ ! -f ../bpf/xdp_dummy.o ]; then
220	echo "Missing xdp_dummy helper. Build bpf selftest first"
221	exit 1
222fi
223
224[ $CPUS -lt 2 ] && echo "Only one CPU available, some tests will be skipped"
225[ $STRESS -gt 0 -a $CPUS -lt 3 ] && echo " stress test will be skipped, too"
226
227create_ns
228chk_gro_flag "default - gro flag" $SRC off
229chk_gro_flag "        - peer gro flag" $DST off
230chk_tso_flag "        - tso flag" $SRC on
231chk_tso_flag "        - peer tso flag" $DST on
232chk_gro "        - aggregation" 1
233ip netns exec $NS_SRC ethtool -K veth$SRC tx-udp-segmentation off
234chk_gro "        - aggregation with TSO off" 10
235cleanup
236
237create_ns
238ip netns exec $NS_DST ethtool -K veth$DST gro on
239chk_gro_flag "with gro on - gro flag" $DST on
240chk_gro_flag "        - peer gro flag" $SRC off
241chk_tso_flag "        - tso flag" $SRC on
242chk_tso_flag "        - peer tso flag" $DST on
243ip netns exec $NS_SRC ethtool -K veth$SRC tx-udp-segmentation off
244ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
245chk_gro "        - aggregation with TSO off" 1
246cleanup
247
248create_ns
249chk_channels "default channels" $DST 1 1
250
251ip -n $NS_DST link set dev veth$DST down
252ip netns exec $NS_DST ethtool -K veth$DST gro on
253chk_gro_flag "with gro enabled on link down - gro flag" $DST on
254chk_gro_flag "        - peer gro flag" $SRC off
255chk_tso_flag "        - tso flag" $SRC on
256chk_tso_flag "        - peer tso flag" $DST on
257ip -n $NS_DST link set dev veth$DST up
258ip netns exec $NS_SRC ethtool -K veth$SRC tx-udp-segmentation off
259ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
260chk_gro "        - aggregation with TSO off" 1
261cleanup
262
263create_ns
264
265CUR_TX=1
266CUR_RX=1
267if [ $CPUS -gt 1 ]; then
268	ip netns exec $NS_DST ethtool -L veth$DST tx 2
269	chk_channels "setting tx channels" $DST 1 2
270	CUR_TX=2
271fi
272
273if [ $CPUS -gt 2 ]; then
274	ip netns exec $NS_DST ethtool -L veth$DST rx 3 tx 3
275	chk_channels "setting both rx and tx channels" $DST 3 3
276	CUR_RX=3
277	CUR_TX=3
278fi
279
280ip netns exec $NS_DST ethtool -L veth$DST combined 2 2>/dev/null
281chk_channels "bad setting: combined channels" $DST $CUR_RX $CUR_TX
282
283ip netns exec $NS_DST ethtool -L veth$DST tx $((CPUS + 1)) 2>/dev/null
284chk_channels "setting invalid channels nr" $DST $CUR_RX $CUR_TX
285
286if [ $CPUS -gt 1 ]; then
287	# this also tests queues nr reduction
288	ip netns exec $NS_DST ethtool -L veth$DST rx 1 tx 2 2>/dev/null
289	ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
290	printf "%-60s" "bad setting: XDP with RX nr less than TX"
291	ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
292		section xdp 2>/dev/null &&\
293		echo "fail - set operation successful ?!?" || echo " ok "
294
295	# the following tests will run with multiple channels active
296	ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
297	ip netns exec $NS_DST ethtool -L veth$DST rx 2
298	ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
299		section xdp 2>/dev/null
300	printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
301	ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
302		echo "fail - set operation successful ?!?" || echo " ok "
303	CUR_RX=2
304	CUR_TX=2
305fi
306
307if [ $CPUS -gt 2 ]; then
308	printf "%-60s" "bad setting: increasing peer TX nr above RX with XDP set"
309	ip netns exec $NS_SRC ethtool -L veth$SRC tx 3 2>/dev/null &&\
310		echo "fail - set operation successful ?!?" || echo " ok "
311	chk_channels "setting invalid channels nr" $DST 2 2
312fi
313
314ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
315chk_gro_flag "with xdp attached - gro flag" $DST on
316chk_gro_flag "        - peer gro flag" $SRC off
317chk_tso_flag "        - tso flag" $SRC off
318chk_tso_flag "        - peer tso flag" $DST on
319ip netns exec $NS_DST ethtool -K veth$DST rx-udp-gro-forwarding on
320chk_gro "        - aggregation" 1
321
322
323ip -n $NS_DST link set dev veth$DST down
324ip -n $NS_SRC link set dev veth$SRC down
325chk_gro_flag "        - after dev off, flag" $DST on
326chk_gro_flag "        - peer flag" $SRC off
327
328ip netns exec $NS_DST ethtool -K veth$DST gro on
329ip -n $NS_DST link set dev veth$DST xdp off
330chk_gro_flag "        - after gro on xdp off, gro flag" $DST on
331chk_gro_flag "        - peer gro flag" $SRC off
332chk_tso_flag "        - tso flag" $SRC on
333chk_tso_flag "        - peer tso flag" $DST on
334
335if [ $CPUS -gt 1 ]; then
336	ip netns exec $NS_DST ethtool -L veth$DST tx 1
337	chk_channels "decreasing tx channels with device down" $DST 2 1
338fi
339
340ip -n $NS_DST link set dev veth$DST up
341ip -n $NS_SRC link set dev veth$SRC up
342chk_gro "        - aggregation" 1
343
344if [ $CPUS -gt 1 ]; then
345	[ $STRESS -gt 0 -a $CPUS -gt 2 ] && do_stress
346
347	ip -n $NS_DST link set dev veth$DST down
348	ip -n $NS_SRC link set dev veth$SRC down
349	ip netns exec $NS_DST ethtool -L veth$DST tx 2
350	chk_channels "increasing tx channels with device down" $DST 2 2
351	ip -n $NS_DST link set dev veth$DST up
352	ip -n $NS_SRC link set dev veth$SRC up
353fi
354
355ip netns exec $NS_DST ethtool -K veth$DST gro off
356ip netns exec $NS_SRC ethtool -K veth$SRC tx-udp-segmentation off
357chk_gro "aggregation again with default and TSO off" 10
358
359exit $ret
360