Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Setup/topology:
5#
6# NS1 NS2 NS3
7# veth1 <---> veth2 veth3 <---> veth4 (the top route)
8# veth5 <---> veth6 veth7 <---> veth8 (the bottom route)
9#
10# each vethN gets IPv[4|6]_N address
11#
12# IPv*_SRC = IPv*_1
13# IPv*_DST = IPv*_4
14#
15# all tests test pings from IPv*_SRC to IPv*_DST
16#
17# by default, routes are configured to allow packets to go
18# IP*_1 <=> IP*_2 <=> IP*_3 <=> IP*_4 (the top route)
19#
20# a GRE device is installed in NS3 with IPv*_GRE, and
21# NS1/NS2 are configured to route packets to IPv*_GRE via IP*_8
22# (the bottom route)
23#
24# Tests:
25#
26# 1. routes NS2->IPv*_DST are brought down, so the only way a ping
27# from IP*_SRC to IP*_DST can work is via IPv*_GRE
28#
29# 2a. in an egress test, a bpf LWT_XMIT program is installed on veth1
30# that encaps the packets with an IP/GRE header to route to IPv*_GRE
31#
32# ping: SRC->[encap at veth1:egress]->GRE:decap->DST
33# ping replies go DST->SRC directly
34#
35# 2b. in an ingress test, a bpf LWT_IN program is installed on veth2
36# that encaps the packets with an IP/GRE header to route to IPv*_GRE
37#
38# ping: SRC->[encap at veth2:ingress]->GRE:decap->DST
39# ping replies go DST->SRC directly
40
41if [[ $EUID -ne 0 ]]; then
42 echo "This script must be run as root"
43 echo "FAIL"
44 exit 1
45fi
46
47readonly NS1="ns1-$(mktemp -u XXXXXX)"
48readonly NS2="ns2-$(mktemp -u XXXXXX)"
49readonly NS3="ns3-$(mktemp -u XXXXXX)"
50
51readonly IPv4_1="172.16.1.100"
52readonly IPv4_2="172.16.2.100"
53readonly IPv4_3="172.16.3.100"
54readonly IPv4_4="172.16.4.100"
55readonly IPv4_5="172.16.5.100"
56readonly IPv4_6="172.16.6.100"
57readonly IPv4_7="172.16.7.100"
58readonly IPv4_8="172.16.8.100"
59readonly IPv4_GRE="172.16.16.100"
60
61readonly IPv4_SRC=$IPv4_1
62readonly IPv4_DST=$IPv4_4
63
64readonly IPv6_1="fb01::1"
65readonly IPv6_2="fb02::1"
66readonly IPv6_3="fb03::1"
67readonly IPv6_4="fb04::1"
68readonly IPv6_5="fb05::1"
69readonly IPv6_6="fb06::1"
70readonly IPv6_7="fb07::1"
71readonly IPv6_8="fb08::1"
72readonly IPv6_GRE="fb10::1"
73
74readonly IPv6_SRC=$IPv6_1
75readonly IPv6_DST=$IPv6_4
76
77TEST_STATUS=0
78TESTS_SUCCEEDED=0
79TESTS_FAILED=0
80
81TMPFILE=""
82
83process_test_results()
84{
85 if [[ "${TEST_STATUS}" -eq 0 ]] ; then
86 echo "PASS"
87 TESTS_SUCCEEDED=$((TESTS_SUCCEEDED+1))
88 else
89 echo "FAIL"
90 TESTS_FAILED=$((TESTS_FAILED+1))
91 fi
92}
93
94print_test_summary_and_exit()
95{
96 echo "passed tests: ${TESTS_SUCCEEDED}"
97 echo "failed tests: ${TESTS_FAILED}"
98 if [ "${TESTS_FAILED}" -eq "0" ] ; then
99 exit 0
100 else
101 exit 1
102 fi
103}
104
105setup()
106{
107 set -e # exit on error
108 TEST_STATUS=0
109
110 # create devices and namespaces
111 ip netns add "${NS1}"
112 ip netns add "${NS2}"
113 ip netns add "${NS3}"
114
115 ip link add veth1 type veth peer name veth2
116 ip link add veth3 type veth peer name veth4
117 ip link add veth5 type veth peer name veth6
118 ip link add veth7 type veth peer name veth8
119
120 ip netns exec ${NS2} sysctl -wq net.ipv4.ip_forward=1
121 ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.forwarding=1
122
123 ip link set veth1 netns ${NS1}
124 ip link set veth2 netns ${NS2}
125 ip link set veth3 netns ${NS2}
126 ip link set veth4 netns ${NS3}
127 ip link set veth5 netns ${NS1}
128 ip link set veth6 netns ${NS2}
129 ip link set veth7 netns ${NS2}
130 ip link set veth8 netns ${NS3}
131
132 # configure addesses: the top route (1-2-3-4)
133 ip -netns ${NS1} addr add ${IPv4_1}/24 dev veth1
134 ip -netns ${NS2} addr add ${IPv4_2}/24 dev veth2
135 ip -netns ${NS2} addr add ${IPv4_3}/24 dev veth3
136 ip -netns ${NS3} addr add ${IPv4_4}/24 dev veth4
137 ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1
138 ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2
139 ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3
140 ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4
141
142 # configure addresses: the bottom route (5-6-7-8)
143 ip -netns ${NS1} addr add ${IPv4_5}/24 dev veth5
144 ip -netns ${NS2} addr add ${IPv4_6}/24 dev veth6
145 ip -netns ${NS2} addr add ${IPv4_7}/24 dev veth7
146 ip -netns ${NS3} addr add ${IPv4_8}/24 dev veth8
147 ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5
148 ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6
149 ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7
150 ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8
151
152 ip -netns ${NS1} link set dev veth1 up
153 ip -netns ${NS2} link set dev veth2 up
154 ip -netns ${NS2} link set dev veth3 up
155 ip -netns ${NS3} link set dev veth4 up
156 ip -netns ${NS1} link set dev veth5 up
157 ip -netns ${NS2} link set dev veth6 up
158 ip -netns ${NS2} link set dev veth7 up
159 ip -netns ${NS3} link set dev veth8 up
160
161 # configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;
162 # the bottom route to specific bottom addresses
163
164 # NS1
165 # top route
166 ip -netns ${NS1} route add ${IPv4_2}/32 dev veth1
167 ip -netns ${NS1} route add default dev veth1 via ${IPv4_2} # go top by default
168 ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1
169 ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} # go top by default
170 # bottom route
171 ip -netns ${NS1} route add ${IPv4_6}/32 dev veth5
172 ip -netns ${NS1} route add ${IPv4_7}/32 dev veth5 via ${IPv4_6}
173 ip -netns ${NS1} route add ${IPv4_8}/32 dev veth5 via ${IPv4_6}
174 ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5
175 ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6}
176 ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6}
177
178 # NS2
179 # top route
180 ip -netns ${NS2} route add ${IPv4_1}/32 dev veth2
181 ip -netns ${NS2} route add ${IPv4_4}/32 dev veth3
182 ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2
183 ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3
184 # bottom route
185 ip -netns ${NS2} route add ${IPv4_5}/32 dev veth6
186 ip -netns ${NS2} route add ${IPv4_8}/32 dev veth7
187 ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6
188 ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7
189
190 # NS3
191 # top route
192 ip -netns ${NS3} route add ${IPv4_3}/32 dev veth4
193 ip -netns ${NS3} route add ${IPv4_1}/32 dev veth4 via ${IPv4_3}
194 ip -netns ${NS3} route add ${IPv4_2}/32 dev veth4 via ${IPv4_3}
195 ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4
196 ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}
197 ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}
198 # bottom route
199 ip -netns ${NS3} route add ${IPv4_7}/32 dev veth8
200 ip -netns ${NS3} route add ${IPv4_5}/32 dev veth8 via ${IPv4_7}
201 ip -netns ${NS3} route add ${IPv4_6}/32 dev veth8 via ${IPv4_7}
202 ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8
203 ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}
204 ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}
205
206 # configure IPv4 GRE device in NS3, and a route to it via the "bottom" route
207 ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255
208 ip -netns ${NS3} link set gre_dev up
209 ip -netns ${NS3} addr add ${IPv4_GRE} dev gre_dev
210 ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6}
211 ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8}
212
213
214 # configure IPv6 GRE device in NS3, and a route to it via the "bottom" route
215 ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255
216 ip -netns ${NS3} link set gre6_dev up
217 ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev
218 ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6}
219 ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8}
220
221 # rp_filter gets confused by what these tests are doing, so disable it
222 ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0
223 ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0
224 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0
225
226 TMPFILE=$(mktemp /tmp/test_lwt_ip_encap.XXXXXX)
227
228 sleep 1 # reduce flakiness
229 set +e
230}
231
232cleanup()
233{
234 if [ -f ${TMPFILE} ] ; then
235 rm ${TMPFILE}
236 fi
237
238 ip netns del ${NS1} 2> /dev/null
239 ip netns del ${NS2} 2> /dev/null
240 ip netns del ${NS3} 2> /dev/null
241}
242
243trap cleanup EXIT
244
245remove_routes_to_gredev()
246{
247 ip -netns ${NS1} route del ${IPv4_GRE} dev veth5
248 ip -netns ${NS2} route del ${IPv4_GRE} dev veth7
249 ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5
250 ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7
251}
252
253add_unreachable_routes_to_gredev()
254{
255 ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32
256 ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32
257 ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128
258 ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128
259}
260
261test_ping()
262{
263 local readonly PROTO=$1
264 local readonly EXPECTED=$2
265 local RET=0
266
267 if [ "${PROTO}" == "IPv4" ] ; then
268 ip netns exec ${NS1} ping -c 1 -W 1 -I ${IPv4_SRC} ${IPv4_DST} 2>&1 > /dev/null
269 RET=$?
270 elif [ "${PROTO}" == "IPv6" ] ; then
271 ip netns exec ${NS1} ping6 -c 1 -W 6 -I ${IPv6_SRC} ${IPv6_DST} 2>&1 > /dev/null
272 RET=$?
273 else
274 echo " test_ping: unknown PROTO: ${PROTO}"
275 TEST_STATUS=1
276 fi
277
278 if [ "0" != "${RET}" ]; then
279 RET=1
280 fi
281
282 if [ "${EXPECTED}" != "${RET}" ] ; then
283 echo " test_ping failed: expected: ${EXPECTED}; got ${RET}"
284 TEST_STATUS=1
285 fi
286}
287
288test_gso()
289{
290 local readonly PROTO=$1
291 local readonly PKT_SZ=5000
292 local IP_DST=""
293 : > ${TMPFILE} # trim the capture file
294
295 # check that nc is present
296 command -v nc >/dev/null 2>&1 || \
297 { echo >&2 "nc is not available: skipping TSO tests"; return; }
298
299 # listen on IPv*_DST, capture TCP into $TMPFILE
300 if [ "${PROTO}" == "IPv4" ] ; then
301 IP_DST=${IPv4_DST}
302 ip netns exec ${NS3} bash -c \
303 "nc -4 -l -s ${IPv4_DST} -p 9000 > ${TMPFILE} &"
304 elif [ "${PROTO}" == "IPv6" ] ; then
305 IP_DST=${IPv6_DST}
306 ip netns exec ${NS3} bash -c \
307 "nc -6 -l -s ${IPv6_DST} -p 9000 > ${TMPFILE} &"
308 RET=$?
309 else
310 echo " test_gso: unknown PROTO: ${PROTO}"
311 TEST_STATUS=1
312 fi
313 sleep 1 # let nc start listening
314
315 # send a packet larger than MTU
316 ip netns exec ${NS1} bash -c \
317 "dd if=/dev/zero bs=$PKT_SZ count=1 > /dev/tcp/${IP_DST}/9000 2>/dev/null"
318 sleep 2 # let the packet get delivered
319
320 # verify we received all expected bytes
321 SZ=$(stat -c %s ${TMPFILE})
322 if [ "$SZ" != "$PKT_SZ" ] ; then
323 echo " test_gso failed: ${PROTO}"
324 TEST_STATUS=1
325 fi
326}
327
328test_egress()
329{
330 local readonly ENCAP=$1
331 echo "starting egress ${ENCAP} encap test"
332 setup
333
334 # by default, pings work
335 test_ping IPv4 0
336 test_ping IPv6 0
337
338 # remove NS2->DST routes, ping fails
339 ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3
340 ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3
341 test_ping IPv4 1
342 test_ping IPv6 1
343
344 # install replacement routes (LWT/eBPF), pings succeed
345 if [ "${ENCAP}" == "IPv4" ] ; then
346 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre dev veth1
347 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre dev veth1
348 elif [ "${ENCAP}" == "IPv6" ] ; then
349 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre6 dev veth1
350 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre6 dev veth1
351 else
352 echo " unknown encap ${ENCAP}"
353 TEST_STATUS=1
354 fi
355 test_ping IPv4 0
356 test_ping IPv6 0
357 test_gso IPv4
358 test_gso IPv6
359
360 # a negative test: remove routes to GRE devices: ping fails
361 remove_routes_to_gredev
362 test_ping IPv4 1
363 test_ping IPv6 1
364
365 # another negative test
366 add_unreachable_routes_to_gredev
367 test_ping IPv4 1
368 test_ping IPv6 1
369
370 cleanup
371 process_test_results
372}
373
374test_ingress()
375{
376 local readonly ENCAP=$1
377 echo "starting ingress ${ENCAP} encap test"
378 setup
379
380 # need to wait a bit for IPv6 to autoconf, otherwise
381 # ping6 sometimes fails with "unable to bind to address"
382
383 # by default, pings work
384 test_ping IPv4 0
385 test_ping IPv6 0
386
387 # remove NS2->DST routes, pings fail
388 ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3
389 ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3
390 test_ping IPv4 1
391 test_ping IPv6 1
392
393 # install replacement routes (LWT/eBPF), pings succeed
394 if [ "${ENCAP}" == "IPv4" ] ; then
395 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre dev veth2
396 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre dev veth2
397 elif [ "${ENCAP}" == "IPv6" ] ; then
398 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre6 dev veth2
399 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre6 dev veth2
400 else
401 echo "FAIL: unknown encap ${ENCAP}"
402 TEST_STATUS=1
403 fi
404 test_ping IPv4 0
405 test_ping IPv6 0
406
407 # a negative test: remove routes to GRE devices: ping fails
408 remove_routes_to_gredev
409 test_ping IPv4 1
410 test_ping IPv6 1
411
412 # another negative test
413 add_unreachable_routes_to_gredev
414 test_ping IPv4 1
415 test_ping IPv6 1
416
417 cleanup
418 process_test_results
419}
420
421test_egress IPv4
422test_egress IPv6
423test_ingress IPv4
424test_ingress IPv6
425
426print_test_summary_and_exit