xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/bpf/test_tc_tunnel.sh (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun#!/bin/bash
2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0
3*4882a593Smuzhiyun#
4*4882a593Smuzhiyun# In-place tunneling
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun# must match the port that the bpf program filters on
7*4882a593Smuzhiyunreadonly port=8000
8*4882a593Smuzhiyun
9*4882a593Smuzhiyunreadonly ns_prefix="ns-$$-"
10*4882a593Smuzhiyunreadonly ns1="${ns_prefix}1"
11*4882a593Smuzhiyunreadonly ns2="${ns_prefix}2"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyunreadonly ns1_v4=192.168.1.1
14*4882a593Smuzhiyunreadonly ns2_v4=192.168.1.2
15*4882a593Smuzhiyunreadonly ns1_v6=fd::1
16*4882a593Smuzhiyunreadonly ns2_v6=fd::2
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun# Must match port used by bpf program
19*4882a593Smuzhiyunreadonly udpport=5555
20*4882a593Smuzhiyun# MPLSoverUDP
21*4882a593Smuzhiyunreadonly mplsudpport=6635
22*4882a593Smuzhiyunreadonly mplsproto=137
23*4882a593Smuzhiyun
24*4882a593Smuzhiyunreadonly infile="$(mktemp)"
25*4882a593Smuzhiyunreadonly outfile="$(mktemp)"
26*4882a593Smuzhiyun
27*4882a593Smuzhiyunsetup() {
28*4882a593Smuzhiyun	ip netns add "${ns1}"
29*4882a593Smuzhiyun	ip netns add "${ns2}"
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun	ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \
32*4882a593Smuzhiyun	      peer name veth2 mtu 1500 netns "${ns2}"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun	ip netns exec "${ns1}" ethtool -K veth1 tso off
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun	ip -netns "${ns1}" link set veth1 up
37*4882a593Smuzhiyun	ip -netns "${ns2}" link set veth2 up
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun	ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1
40*4882a593Smuzhiyun	ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2
41*4882a593Smuzhiyun	ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad
42*4882a593Smuzhiyun	ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun	# clamp route to reserve room for tunnel headers
45*4882a593Smuzhiyun	ip -netns "${ns1}" -4 route flush table main
46*4882a593Smuzhiyun	ip -netns "${ns1}" -6 route flush table main
47*4882a593Smuzhiyun	ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1458 dev veth1
48*4882a593Smuzhiyun	ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1438 dev veth1
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun	sleep 1
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun	dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none
53*4882a593Smuzhiyun}
54*4882a593Smuzhiyun
55*4882a593Smuzhiyuncleanup() {
56*4882a593Smuzhiyun	ip netns del "${ns2}"
57*4882a593Smuzhiyun	ip netns del "${ns1}"
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun	if [[ -f "${outfile}" ]]; then
60*4882a593Smuzhiyun		rm "${outfile}"
61*4882a593Smuzhiyun	fi
62*4882a593Smuzhiyun	if [[ -f "${infile}" ]]; then
63*4882a593Smuzhiyun		rm "${infile}"
64*4882a593Smuzhiyun	fi
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun	if [[ -n $server_pid ]]; then
67*4882a593Smuzhiyun		kill $server_pid 2> /dev/null
68*4882a593Smuzhiyun	fi
69*4882a593Smuzhiyun}
70*4882a593Smuzhiyun
71*4882a593Smuzhiyunserver_listen() {
72*4882a593Smuzhiyun	ip netns exec "${ns2}" nc "${netcat_opt}" -l -p "${port}" > "${outfile}" &
73*4882a593Smuzhiyun	server_pid=$!
74*4882a593Smuzhiyun	sleep 0.2
75*4882a593Smuzhiyun}
76*4882a593Smuzhiyun
77*4882a593Smuzhiyunclient_connect() {
78*4882a593Smuzhiyun	ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}"
79*4882a593Smuzhiyun	echo $?
80*4882a593Smuzhiyun}
81*4882a593Smuzhiyun
82*4882a593Smuzhiyunverify_data() {
83*4882a593Smuzhiyun	wait "${server_pid}"
84*4882a593Smuzhiyun	server_pid=
85*4882a593Smuzhiyun	# sha1sum returns two fields [sha1] [filepath]
86*4882a593Smuzhiyun	# convert to bash array and access first elem
87*4882a593Smuzhiyun	insum=($(sha1sum ${infile}))
88*4882a593Smuzhiyun	outsum=($(sha1sum ${outfile}))
89*4882a593Smuzhiyun	if [[ "${insum[0]}" != "${outsum[0]}" ]]; then
90*4882a593Smuzhiyun		echo "data mismatch"
91*4882a593Smuzhiyun		exit 1
92*4882a593Smuzhiyun	fi
93*4882a593Smuzhiyun}
94*4882a593Smuzhiyun
95*4882a593Smuzhiyunset -e
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun# no arguments: automated test, run all
98*4882a593Smuzhiyunif [[ "$#" -eq "0" ]]; then
99*4882a593Smuzhiyun	echo "ipip"
100*4882a593Smuzhiyun	$0 ipv4 ipip none 100
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun	echo "ip6ip6"
103*4882a593Smuzhiyun	$0 ipv6 ip6tnl none 100
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun	echo "sit"
106*4882a593Smuzhiyun	$0 ipv6 sit none 100
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun	for mac in none mpls eth ; do
109*4882a593Smuzhiyun		echo "ip gre $mac"
110*4882a593Smuzhiyun		$0 ipv4 gre $mac 100
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun		echo "ip6 gre $mac"
113*4882a593Smuzhiyun		$0 ipv6 ip6gre $mac 100
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun		echo "ip gre $mac gso"
116*4882a593Smuzhiyun		$0 ipv4 gre $mac 2000
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun		echo "ip6 gre $mac gso"
119*4882a593Smuzhiyun		$0 ipv6 ip6gre $mac 2000
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun		echo "ip udp $mac"
122*4882a593Smuzhiyun		$0 ipv4 udp $mac 100
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun		echo "ip6 udp $mac"
125*4882a593Smuzhiyun		$0 ipv6 ip6udp $mac 100
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun		echo "ip udp $mac gso"
128*4882a593Smuzhiyun		$0 ipv4 udp $mac 2000
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun		echo "ip6 udp $mac gso"
131*4882a593Smuzhiyun		$0 ipv6 ip6udp $mac 2000
132*4882a593Smuzhiyun	done
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun	echo "OK. All tests passed"
135*4882a593Smuzhiyun	exit 0
136*4882a593Smuzhiyunfi
137*4882a593Smuzhiyun
138*4882a593Smuzhiyunif [[ "$#" -ne "4" ]]; then
139*4882a593Smuzhiyun	echo "Usage: $0"
140*4882a593Smuzhiyun	echo "   or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>"
141*4882a593Smuzhiyun	exit 1
142*4882a593Smuzhiyunfi
143*4882a593Smuzhiyun
144*4882a593Smuzhiyuncase "$1" in
145*4882a593Smuzhiyun"ipv4")
146*4882a593Smuzhiyun	readonly addr1="${ns1_v4}"
147*4882a593Smuzhiyun	readonly addr2="${ns2_v4}"
148*4882a593Smuzhiyun	readonly ipproto=4
149*4882a593Smuzhiyun	readonly netcat_opt=-${ipproto}
150*4882a593Smuzhiyun	readonly foumod=fou
151*4882a593Smuzhiyun	readonly foutype=ipip
152*4882a593Smuzhiyun	readonly fouproto=4
153*4882a593Smuzhiyun	readonly fouproto_mpls=${mplsproto}
154*4882a593Smuzhiyun	readonly gretaptype=gretap
155*4882a593Smuzhiyun	;;
156*4882a593Smuzhiyun"ipv6")
157*4882a593Smuzhiyun	readonly addr1="${ns1_v6}"
158*4882a593Smuzhiyun	readonly addr2="${ns2_v6}"
159*4882a593Smuzhiyun	readonly ipproto=6
160*4882a593Smuzhiyun	readonly netcat_opt=-${ipproto}
161*4882a593Smuzhiyun	readonly foumod=fou6
162*4882a593Smuzhiyun	readonly foutype=ip6tnl
163*4882a593Smuzhiyun	readonly fouproto="41 -6"
164*4882a593Smuzhiyun	readonly fouproto_mpls="${mplsproto} -6"
165*4882a593Smuzhiyun	readonly gretaptype=ip6gretap
166*4882a593Smuzhiyun	;;
167*4882a593Smuzhiyun*)
168*4882a593Smuzhiyun	echo "unknown arg: $1"
169*4882a593Smuzhiyun	exit 1
170*4882a593Smuzhiyun	;;
171*4882a593Smuzhiyunesac
172*4882a593Smuzhiyun
173*4882a593Smuzhiyunreadonly tuntype=$2
174*4882a593Smuzhiyunreadonly mac=$3
175*4882a593Smuzhiyunreadonly datalen=$4
176*4882a593Smuzhiyun
177*4882a593Smuzhiyunecho "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}"
178*4882a593Smuzhiyun
179*4882a593Smuzhiyuntrap cleanup EXIT
180*4882a593Smuzhiyun
181*4882a593Smuzhiyunsetup
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun# basic communication works
184*4882a593Smuzhiyunecho "test basic connectivity"
185*4882a593Smuzhiyunserver_listen
186*4882a593Smuzhiyunclient_connect
187*4882a593Smuzhiyunverify_data
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun# clientside, insert bpf program to encap all TCP to port ${port}
190*4882a593Smuzhiyun# client can no longer connect
191*4882a593Smuzhiyunip netns exec "${ns1}" tc qdisc add dev veth1 clsact
192*4882a593Smuzhiyunip netns exec "${ns1}" tc filter add dev veth1 egress \
193*4882a593Smuzhiyun	bpf direct-action object-file ./test_tc_tunnel.o \
194*4882a593Smuzhiyun	section "encap_${tuntype}_${mac}"
195*4882a593Smuzhiyunecho "test bpf encap without decap (expect failure)"
196*4882a593Smuzhiyunserver_listen
197*4882a593Smuzhiyun! client_connect
198*4882a593Smuzhiyun
199*4882a593Smuzhiyunif [[ "$tuntype" =~ "udp" ]]; then
200*4882a593Smuzhiyun	# Set up fou tunnel.
201*4882a593Smuzhiyun	ttype="${foutype}"
202*4882a593Smuzhiyun	targs="encap fou encap-sport auto encap-dport $udpport"
203*4882a593Smuzhiyun	# fou may be a module; allow this to fail.
204*4882a593Smuzhiyun	modprobe "${foumod}" ||true
205*4882a593Smuzhiyun	if [[ "$mac" == "mpls" ]]; then
206*4882a593Smuzhiyun		dport=${mplsudpport}
207*4882a593Smuzhiyun		dproto=${fouproto_mpls}
208*4882a593Smuzhiyun		tmode="mode any ttl 255"
209*4882a593Smuzhiyun	else
210*4882a593Smuzhiyun		dport=${udpport}
211*4882a593Smuzhiyun		dproto=${fouproto}
212*4882a593Smuzhiyun	fi
213*4882a593Smuzhiyun	ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto}
214*4882a593Smuzhiyun	targs="encap fou encap-sport auto encap-dport $dport"
215*4882a593Smuzhiyunelif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
216*4882a593Smuzhiyun	ttype=$gretaptype
217*4882a593Smuzhiyunelse
218*4882a593Smuzhiyun	ttype=$tuntype
219*4882a593Smuzhiyun	targs=""
220*4882a593Smuzhiyunfi
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun# tunnel address family differs from inner for SIT
223*4882a593Smuzhiyunif [[ "${tuntype}" == "sit" ]]; then
224*4882a593Smuzhiyun	link_addr1="${ns1_v4}"
225*4882a593Smuzhiyun	link_addr2="${ns2_v4}"
226*4882a593Smuzhiyunelse
227*4882a593Smuzhiyun	link_addr1="${addr1}"
228*4882a593Smuzhiyun	link_addr2="${addr2}"
229*4882a593Smuzhiyunfi
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun# serverside, insert decap module
232*4882a593Smuzhiyun# server is still running
233*4882a593Smuzhiyun# client can connect again
234*4882a593Smuzhiyunip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \
235*4882a593Smuzhiyun	${tmode} remote "${link_addr1}" local "${link_addr2}" $targs
236*4882a593Smuzhiyun
237*4882a593Smuzhiyunexpect_tun_fail=0
238*4882a593Smuzhiyun
239*4882a593Smuzhiyunif [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then
240*4882a593Smuzhiyun	# No support for MPLS IPv6 fou tunnel; expect failure.
241*4882a593Smuzhiyun	expect_tun_fail=1
242*4882a593Smuzhiyunelif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then
243*4882a593Smuzhiyun	# No support for TEB fou tunnel; expect failure.
244*4882a593Smuzhiyun	expect_tun_fail=1
245*4882a593Smuzhiyunelif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
246*4882a593Smuzhiyun	# Share ethernet address between tunnel/veth2 so L2 decap works.
247*4882a593Smuzhiyun	ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \
248*4882a593Smuzhiyun		  awk '/ether/ { print $2 }')
249*4882a593Smuzhiyun	ip netns exec "${ns2}" ip link set testtun0 address $ethaddr
250*4882a593Smuzhiyunelif [[ "$mac" == "mpls" ]]; then
251*4882a593Smuzhiyun	modprobe mpls_iptunnel ||true
252*4882a593Smuzhiyun	modprobe mpls_gso ||true
253*4882a593Smuzhiyun	ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536
254*4882a593Smuzhiyun	ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo
255*4882a593Smuzhiyun	ip netns exec "${ns2}" ip link set lo up
256*4882a593Smuzhiyun	ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1
257*4882a593Smuzhiyun	ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0
258*4882a593Smuzhiyunfi
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun# Because packets are decapped by the tunnel they arrive on testtun0 from
261*4882a593Smuzhiyun# the IP stack perspective.  Ensure reverse path filtering is disabled
262*4882a593Smuzhiyun# otherwise we drop the TCP SYN as arriving on testtun0 instead of the
263*4882a593Smuzhiyun# expected veth2 (veth2 is where 192.168.1.2 is configured).
264*4882a593Smuzhiyunip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0
265*4882a593Smuzhiyun# rp needs to be disabled for both all and testtun0 as the rp value is
266*4882a593Smuzhiyun# selected as the max of the "all" and device-specific values.
267*4882a593Smuzhiyunip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0
268*4882a593Smuzhiyunip netns exec "${ns2}" ip link set dev testtun0 up
269*4882a593Smuzhiyunif [[ "$expect_tun_fail" == 1 ]]; then
270*4882a593Smuzhiyun	# This tunnel mode is not supported, so we expect failure.
271*4882a593Smuzhiyun	echo "test bpf encap with tunnel device decap (expect failure)"
272*4882a593Smuzhiyun	! client_connect
273*4882a593Smuzhiyunelse
274*4882a593Smuzhiyun	echo "test bpf encap with tunnel device decap"
275*4882a593Smuzhiyun	client_connect
276*4882a593Smuzhiyun	verify_data
277*4882a593Smuzhiyun	server_listen
278*4882a593Smuzhiyunfi
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun# bpf_skb_net_shrink does not take tunnel flags yet, cannot update L3.
281*4882a593Smuzhiyunif [[ "${tuntype}" == "sit" ]]; then
282*4882a593Smuzhiyun	echo OK
283*4882a593Smuzhiyun	exit 0
284*4882a593Smuzhiyunfi
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun# serverside, use BPF for decap
287*4882a593Smuzhiyunip netns exec "${ns2}" ip link del dev testtun0
288*4882a593Smuzhiyunip netns exec "${ns2}" tc qdisc add dev veth2 clsact
289*4882a593Smuzhiyunip netns exec "${ns2}" tc filter add dev veth2 ingress \
290*4882a593Smuzhiyun	bpf direct-action object-file ./test_tc_tunnel.o section decap
291*4882a593Smuzhiyunecho "test bpf encap with bpf decap"
292*4882a593Smuzhiyunclient_connect
293*4882a593Smuzhiyunverify_data
294*4882a593Smuzhiyun
295*4882a593Smuzhiyunecho OK
296