aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/bpf/test_tc_tunnel.sh
blob: 64f30910d39a5b7e63853322c54c0e7c261eb780 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# In-place tunneling

# must match the port that the bpf program filters on
readonly port=8000

readonly ns_prefix="ns-$$-"
readonly ns1="${ns_prefix}1"
readonly ns2="${ns_prefix}2"

readonly ns1_v4=192.168.1.1
readonly ns2_v4=192.168.1.2
readonly ns1_v6=fd::1
readonly ns2_v6=fd::2

# Must match port used by bpf program
readonly udpport=5555

readonly infile="$(mktemp)"
readonly outfile="$(mktemp)"

setup() {
	ip netns add "${ns1}"
	ip netns add "${ns2}"

	ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \
	      peer name veth2 mtu 1500 netns "${ns2}"

	ip netns exec "${ns1}" ethtool -K veth1 tso off

	ip -netns "${ns1}" link set veth1 up
	ip -netns "${ns2}" link set veth2 up

	ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1
	ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2
	ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad
	ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad

	# clamp route to reserve room for tunnel headers
	ip -netns "${ns1}" -4 route flush table main
	ip -netns "${ns1}" -6 route flush table main
	ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1472 dev veth1
	ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1452 dev veth1

	sleep 1

	dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none
}

cleanup() {
	ip netns del "${ns2}"
	ip netns del "${ns1}"

	if [[ -f "${outfile}" ]]; then
		rm "${outfile}"
	fi
	if [[ -f "${infile}" ]]; then
		rm "${infile}"
	fi
}

server_listen() {
	ip netns exec "${ns2}" nc "${netcat_opt}" -l -p "${port}" > "${outfile}" &
	server_pid=$!
	sleep 0.2
}

client_connect() {
	ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}"
	echo $?
}

verify_data() {
	wait "${server_pid}"
	# sha1sum returns two fields [sha1] [filepath]
	# convert to bash array and access first elem
	insum=($(sha1sum ${infile}))
	outsum=($(sha1sum ${outfile}))
	if [[ "${insum[0]}" != "${outsum[0]}" ]]; then
		echo "data mismatch"
		exit 1
	fi
}

set -e

# no arguments: automated test, run all
if [[ "$#" -eq "0" ]]; then
	echo "ipip"
	$0 ipv4 ipip 100

	echo "ip6ip6"
	$0 ipv6 ip6tnl 100

	echo "ip gre"
	$0 ipv4 gre 100

	echo "ip6 gre"
	$0 ipv6 ip6gre 100

	echo "ip gre gso"
	$0 ipv4 gre 2000

	echo "ip6 gre gso"
	$0 ipv6 ip6gre 2000

	echo "ip udp"
	$0 ipv4 udp 100

	echo "ip6 udp"
	$0 ipv6 ip6udp 100

	echo "ip udp gso"
	$0 ipv4 udp 2000

	echo "ip6 udp gso"
	$0 ipv6 ip6udp 2000

	echo "OK. All tests passed"
	exit 0
fi

if [[ "$#" -ne "3" ]]; then
	echo "Usage: $0"
	echo "   or: $0 <ipv4|ipv6> <tuntype> <data_len>"
	exit 1
fi

case "$1" in
"ipv4")
	readonly addr1="${ns1_v4}"
	readonly addr2="${ns2_v4}"
	readonly ipproto=4
	readonly netcat_opt=-${ipproto}
	readonly foumod=fou
	readonly foutype=ipip
	readonly fouproto=4
	;;
"ipv6")
	readonly addr1="${ns1_v6}"
	readonly addr2="${ns2_v6}"
	readonly ipproto=6
	readonly netcat_opt=-${ipproto}
	readonly foumod=fou6
	readonly foutype=ip6tnl
	readonly fouproto="41 -6"
	;;
*)
	echo "unknown arg: $1"
	exit 1
	;;
esac

readonly tuntype=$2
readonly datalen=$3

echo "encap ${addr1} to ${addr2}, type ${tuntype}, len ${datalen}"

trap cleanup EXIT

setup

# basic communication works
echo "test basic connectivity"
server_listen
client_connect
verify_data

# clientside, insert bpf program to encap all TCP to port ${port}
# client can no longer connect
ip netns exec "${ns1}" tc qdisc add dev veth1 clsact
ip netns exec "${ns1}" tc filter add dev veth1 egress \
	bpf direct-action object-file ./test_tc_tunnel.o \
	section "encap_${tuntype}"
echo "test bpf encap without decap (expect failure)"
server_listen
! client_connect

if [[ "$tuntype" =~ "udp" ]]; then
	# Set up fou tunnel.
	ttype="${foutype}"
	targs="encap fou encap-sport auto encap-dport $udpport"
	# fou may be a module; allow this to fail.
	modprobe "${foumod}" ||true
	ip netns exec "${ns2}" ip fou add port 5555 ipproto ${fouproto}
else
	ttype=$tuntype
	targs=""
fi

# serverside, insert decap module
# server is still running
# client can connect again
ip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \
	remote "${addr1}" local "${addr2}" $targs
# Because packets are decapped by the tunnel they arrive on testtun0 from
# the IP stack perspective.  Ensure reverse path filtering is disabled
# otherwise we drop the TCP SYN as arriving on testtun0 instead of the
# expected veth2 (veth2 is where 192.168.1.2 is configured).
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0
# rp needs to be disabled for both all and testtun0 as the rp value is
# selected as the max of the "all" and device-specific values.
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0
ip netns exec "${ns2}" ip link set dev testtun0 up
echo "test bpf encap with tunnel device decap"
client_connect
verify_data

# serverside, use BPF for decap
ip netns exec "${ns2}" ip link del dev testtun0
ip netns exec "${ns2}" tc qdisc add dev veth2 clsact
ip netns exec "${ns2}" tc filter add dev veth2 ingress \
	bpf direct-action object-file ./test_tc_tunnel.o section decap
server_listen
echo "test bpf encap with bpf decap"
client_connect
verify_data

echo OK