1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Run a series of udpgro functional tests.
5
6readonly PEER_NS="ns-peer-$(mktemp -u XXXXXX)"
7
8cleanup() {
9	local -r jobs="$(jobs -p)"
10	local -r ns="$(ip netns list|grep $PEER_NS)"
11
12	[ -n "${jobs}" ] && kill -1 ${jobs} 2>/dev/null
13	[ -n "$ns" ] && ip netns del $ns 2>/dev/null
14}
15trap cleanup EXIT
16
17cfg_veth() {
18	ip netns add "${PEER_NS}"
19	ip -netns "${PEER_NS}" link set lo up
20	ip link add type veth
21	ip link set dev veth0 up
22	ip addr add dev veth0 192.168.1.2/24
23	ip addr add dev veth0 2001:db8::2/64 nodad
24
25	ip link set dev veth1 netns "${PEER_NS}"
26	ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
27	ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
28	ip -netns "${PEER_NS}" link set dev veth1 up
29	ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
30}
31
32run_one() {
33	# use 'rx' as separator between sender args and receiver args
34	local -r all="$@"
35	local -r tx_args=${all%rx*}
36	local -r rx_args=${all#*rx}
37
38	cfg_veth
39
40	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} && \
41		echo "ok" || \
42		echo "failed" &
43
44	# Hack: let bg programs complete the startup
45	sleep 0.1
46	./udpgso_bench_tx ${tx_args}
47	wait $(jobs -p)
48}
49
50run_test() {
51	local -r args=$@
52
53	printf " %-40s" "$1"
54	./in_netns.sh $0 __subprocess $2 rx -G -r $3
55}
56
57run_one_nat() {
58	# use 'rx' as separator between sender args and receiver args
59	local addr1 addr2 pid family="" ipt_cmd=ip6tables
60	local -r all="$@"
61	local -r tx_args=${all%rx*}
62	local -r rx_args=${all#*rx}
63
64	if [[ ${tx_args} = *-4* ]]; then
65		ipt_cmd=iptables
66		family=-4
67		addr1=192.168.1.1
68		addr2=192.168.1.3/24
69	else
70		addr1=2001:db8::1
71		addr2="2001:db8::3/64 nodad"
72	fi
73
74	cfg_veth
75	ip -netns "${PEER_NS}" addr add dev veth1 ${addr2}
76
77	# fool the GRO engine changing the destination address ...
78	ip netns exec "${PEER_NS}" $ipt_cmd -t nat -I PREROUTING -d ${addr1} -j DNAT --to-destination ${addr2%/*}
79
80	# ... so that GRO will match the UDP_GRO enabled socket, but packets
81	# will land on the 'plain' one
82	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -G ${family} -b ${addr1} -n 0 &
83	pid=$!
84	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${family} -b ${addr2%/*} ${rx_args} && \
85		echo "ok" || \
86		echo "failed"&
87
88	sleep 0.1
89	./udpgso_bench_tx ${tx_args}
90	kill -INT $pid
91	wait $(jobs -p)
92}
93
94run_one_2sock() {
95	# use 'rx' as separator between sender args and receiver args
96	local -r all="$@"
97	local -r tx_args=${all%rx*}
98	local -r rx_args=${all#*rx}
99
100	cfg_veth
101
102	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 1000 -R 10 ${rx_args} -p 12345 &
103	ip netns exec "${PEER_NS}" ./udpgso_bench_rx -C 2000 -R 10 ${rx_args} && \
104		echo "ok" || \
105		echo "failed" &
106
107	# Hack: let bg programs complete the startup
108	sleep 0.1
109	./udpgso_bench_tx ${tx_args} -p 12345
110	sleep 0.1
111	# first UDP GSO socket should be closed at this point
112	./udpgso_bench_tx ${tx_args}
113	wait $(jobs -p)
114}
115
116run_nat_test() {
117	local -r args=$@
118
119	printf " %-40s" "$1"
120	./in_netns.sh $0 __subprocess_nat $2 rx -r $3
121}
122
123run_2sock_test() {
124	local -r args=$@
125
126	printf " %-40s" "$1"
127	./in_netns.sh $0 __subprocess_2sock $2 rx -G -r $3
128}
129
130run_all() {
131	local -r core_args="-l 4"
132	local -r ipv4_args="${core_args} -4 -D 192.168.1.1"
133	local -r ipv6_args="${core_args} -6 -D 2001:db8::1"
134
135	echo "ipv4"
136	run_test "no GRO" "${ipv4_args} -M 10 -s 1400" "-4 -n 10 -l 1400"
137
138	# explicitly check we are not receiving UDP_SEGMENT cmsg (-S -1)
139	# when GRO does not take place
140	run_test "no GRO chk cmsg" "${ipv4_args} -M 10 -s 1400" "-4 -n 10 -l 1400 -S -1"
141
142	# the GSO packets are aggregated because:
143	# * veth schedule napi after each xmit
144	# * segmentation happens in BH context, veth napi poll is delayed after
145	#   the transmission of the last segment
146	run_test "GRO" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720"
147	run_test "GRO chk cmsg" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720 -S 1472"
148	run_test "GRO with custom segment size" "${ipv4_args} -M 1 -s 14720 -S 500 " "-4 -n 1 -l 14720"
149	run_test "GRO with custom segment size cmsg" "${ipv4_args} -M 1 -s 14720 -S 500 " "-4 -n 1 -l 14720 -S 500"
150
151	run_nat_test "bad GRO lookup" "${ipv4_args} -M 1 -s 14720 -S 0" "-n 10 -l 1472"
152	run_2sock_test "multiple GRO socks" "${ipv4_args} -M 1 -s 14720 -S 0 " "-4 -n 1 -l 14720 -S 1472"
153
154	echo "ipv6"
155	run_test "no GRO" "${ipv6_args} -M 10 -s 1400" "-n 10 -l 1400"
156	run_test "no GRO chk cmsg" "${ipv6_args} -M 10 -s 1400" "-n 10 -l 1400 -S -1"
157	run_test "GRO" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 1 -l 14520"
158	run_test "GRO chk cmsg" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 1 -l 14520 -S 1452"
159	run_test "GRO with custom segment size" "${ipv6_args} -M 1 -s 14520 -S 500" "-n 1 -l 14520"
160	run_test "GRO with custom segment size cmsg" "${ipv6_args} -M 1 -s 14520 -S 500" "-n 1 -l 14520 -S 500"
161
162	run_nat_test "bad GRO lookup" "${ipv6_args} -M 1 -s 14520 -S 0" "-n 10 -l 1452"
163	run_2sock_test "multiple GRO socks" "${ipv6_args} -M 1 -s 14520 -S 0 " "-n 1 -l 14520 -S 1452"
164}
165
166if [ ! -f ../bpf/xdp_dummy.o ]; then
167	echo "Missing xdp_dummy helper. Build bpf selftest first"
168	exit -1
169fi
170
171if [[ $# -eq 0 ]]; then
172	run_all
173elif [[ $1 == "__subprocess" ]]; then
174	shift
175	run_one $@
176elif [[ $1 == "__subprocess_nat" ]]; then
177	shift
178	run_one_nat $@
179elif [[ $1 == "__subprocess_2sock" ]]; then
180	shift
181	run_one_2sock $@
182fi
183