]> Git Repo - J-linux.git/blob - tools/testing/selftests/bpf/test_lwt_ip_encap.sh
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / tools / testing / selftests / bpf / test_lwt_ip_encap.sh
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
41 BPF_FILE="test_lwt_ip_encap.bpf.o"
42 if [[ $EUID -ne 0 ]]; then
43         echo "This script must be run as root"
44         echo "FAIL"
45         exit 1
46 fi
47
48 readonly NS1="ns1-$(mktemp -u XXXXXX)"
49 readonly NS2="ns2-$(mktemp -u XXXXXX)"
50 readonly NS3="ns3-$(mktemp -u XXXXXX)"
51
52 readonly IPv4_1="172.16.1.100"
53 readonly IPv4_2="172.16.2.100"
54 readonly IPv4_3="172.16.3.100"
55 readonly IPv4_4="172.16.4.100"
56 readonly IPv4_5="172.16.5.100"
57 readonly IPv4_6="172.16.6.100"
58 readonly IPv4_7="172.16.7.100"
59 readonly IPv4_8="172.16.8.100"
60 readonly IPv4_GRE="172.16.16.100"
61
62 readonly IPv4_SRC=$IPv4_1
63 readonly IPv4_DST=$IPv4_4
64
65 readonly IPv6_1="fb01::1"
66 readonly IPv6_2="fb02::1"
67 readonly IPv6_3="fb03::1"
68 readonly IPv6_4="fb04::1"
69 readonly IPv6_5="fb05::1"
70 readonly IPv6_6="fb06::1"
71 readonly IPv6_7="fb07::1"
72 readonly IPv6_8="fb08::1"
73 readonly IPv6_GRE="fb10::1"
74
75 readonly IPv6_SRC=$IPv6_1
76 readonly IPv6_DST=$IPv6_4
77
78 TEST_STATUS=0
79 TESTS_SUCCEEDED=0
80 TESTS_FAILED=0
81
82 TMPFILE=""
83
84 process_test_results()
85 {
86         if [[ "${TEST_STATUS}" -eq 0 ]] ; then
87                 echo "PASS"
88                 TESTS_SUCCEEDED=$((TESTS_SUCCEEDED+1))
89         else
90                 echo "FAIL"
91                 TESTS_FAILED=$((TESTS_FAILED+1))
92         fi
93 }
94
95 print_test_summary_and_exit()
96 {
97         echo "passed tests: ${TESTS_SUCCEEDED}"
98         echo "failed tests: ${TESTS_FAILED}"
99         if [ "${TESTS_FAILED}" -eq "0" ] ; then
100                 exit 0
101         else
102                 exit 1
103         fi
104 }
105
106 setup()
107 {
108         set -e  # exit on error
109         TEST_STATUS=0
110
111         # create devices and namespaces
112         ip netns add "${NS1}"
113         ip netns add "${NS2}"
114         ip netns add "${NS3}"
115
116         # rp_filter gets confused by what these tests are doing, so disable it
117         ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0
118         ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0
119         ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0
120         ip netns exec ${NS1} sysctl -wq net.ipv4.conf.default.rp_filter=0
121         ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=0
122         ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=0
123
124         # disable IPv6 DAD because it sometimes takes too long and fails tests
125         ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=0
126         ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=0
127         ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=0
128         ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=0
129         ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=0
130         ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=0
131
132         ip link add veth1 type veth peer name veth2
133         ip link add veth3 type veth peer name veth4
134         ip link add veth5 type veth peer name veth6
135         ip link add veth7 type veth peer name veth8
136
137         ip netns exec ${NS2} sysctl -wq net.ipv4.ip_forward=1
138         ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.forwarding=1
139
140         ip link set veth1 netns ${NS1}
141         ip link set veth2 netns ${NS2}
142         ip link set veth3 netns ${NS2}
143         ip link set veth4 netns ${NS3}
144         ip link set veth5 netns ${NS1}
145         ip link set veth6 netns ${NS2}
146         ip link set veth7 netns ${NS2}
147         ip link set veth8 netns ${NS3}
148
149         if [ ! -z "${VRF}" ] ; then
150                 ip -netns ${NS1} link add red type vrf table 1001
151                 ip -netns ${NS1} link set red up
152                 ip -netns ${NS1} route add table 1001 unreachable default metric 8192
153                 ip -netns ${NS1} -6 route add table 1001 unreachable default metric 8192
154                 ip -netns ${NS1} link set veth1 vrf red
155                 ip -netns ${NS1} link set veth5 vrf red
156
157                 ip -netns ${NS2} link add red type vrf table 1001
158                 ip -netns ${NS2} link set red up
159                 ip -netns ${NS2} route add table 1001 unreachable default metric 8192
160                 ip -netns ${NS2} -6 route add table 1001 unreachable default metric 8192
161                 ip -netns ${NS2} link set veth2 vrf red
162                 ip -netns ${NS2} link set veth3 vrf red
163                 ip -netns ${NS2} link set veth6 vrf red
164                 ip -netns ${NS2} link set veth7 vrf red
165         fi
166
167         # configure addesses: the top route (1-2-3-4)
168         ip -netns ${NS1}    addr add ${IPv4_1}/24  dev veth1
169         ip -netns ${NS2}    addr add ${IPv4_2}/24  dev veth2
170         ip -netns ${NS2}    addr add ${IPv4_3}/24  dev veth3
171         ip -netns ${NS3}    addr add ${IPv4_4}/24  dev veth4
172         ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1
173         ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2
174         ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3
175         ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4
176
177         # configure addresses: the bottom route (5-6-7-8)
178         ip -netns ${NS1}    addr add ${IPv4_5}/24  dev veth5
179         ip -netns ${NS2}    addr add ${IPv4_6}/24  dev veth6
180         ip -netns ${NS2}    addr add ${IPv4_7}/24  dev veth7
181         ip -netns ${NS3}    addr add ${IPv4_8}/24  dev veth8
182         ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5
183         ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6
184         ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7
185         ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8
186
187         ip -netns ${NS1} link set dev veth1 up
188         ip -netns ${NS2} link set dev veth2 up
189         ip -netns ${NS2} link set dev veth3 up
190         ip -netns ${NS3} link set dev veth4 up
191         ip -netns ${NS1} link set dev veth5 up
192         ip -netns ${NS2} link set dev veth6 up
193         ip -netns ${NS2} link set dev veth7 up
194         ip -netns ${NS3} link set dev veth8 up
195
196         # configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;
197         # the bottom route to specific bottom addresses
198
199         # NS1
200         # top route
201         ip -netns ${NS1}    route add ${IPv4_2}/32  dev veth1 ${VRF}
202         ip -netns ${NS1}    route add default dev veth1 via ${IPv4_2} ${VRF}  # go top by default
203         ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1 ${VRF}
204         ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} ${VRF}  # go top by default
205         # bottom route
206         ip -netns ${NS1}    route add ${IPv4_6}/32  dev veth5 ${VRF}
207         ip -netns ${NS1}    route add ${IPv4_7}/32  dev veth5 via ${IPv4_6} ${VRF}
208         ip -netns ${NS1}    route add ${IPv4_8}/32  dev veth5 via ${IPv4_6} ${VRF}
209         ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5 ${VRF}
210         ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6} ${VRF}
211         ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6} ${VRF}
212
213         # NS2
214         # top route
215         ip -netns ${NS2}    route add ${IPv4_1}/32  dev veth2 ${VRF}
216         ip -netns ${NS2}    route add ${IPv4_4}/32  dev veth3 ${VRF}
217         ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2 ${VRF}
218         ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3 ${VRF}
219         # bottom route
220         ip -netns ${NS2}    route add ${IPv4_5}/32  dev veth6 ${VRF}
221         ip -netns ${NS2}    route add ${IPv4_8}/32  dev veth7 ${VRF}
222         ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6 ${VRF}
223         ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7 ${VRF}
224
225         # NS3
226         # top route
227         ip -netns ${NS3}    route add ${IPv4_3}/32  dev veth4
228         ip -netns ${NS3}    route add ${IPv4_1}/32  dev veth4 via ${IPv4_3}
229         ip -netns ${NS3}    route add ${IPv4_2}/32  dev veth4 via ${IPv4_3}
230         ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4
231         ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}
232         ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}
233         # bottom route
234         ip -netns ${NS3}    route add ${IPv4_7}/32  dev veth8
235         ip -netns ${NS3}    route add ${IPv4_5}/32  dev veth8 via ${IPv4_7}
236         ip -netns ${NS3}    route add ${IPv4_6}/32  dev veth8 via ${IPv4_7}
237         ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8
238         ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}
239         ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}
240
241         # configure IPv4 GRE device in NS3, and a route to it via the "bottom" route
242         ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255
243         ip -netns ${NS3} link set gre_dev up
244         ip -netns ${NS3} addr add ${IPv4_GRE} dev gre_dev
245         ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6} ${VRF}
246         ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8} ${VRF}
247
248
249         # configure IPv6 GRE device in NS3, and a route to it via the "bottom" route
250         ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255
251         ip -netns ${NS3} link set gre6_dev up
252         ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev
253         ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6} ${VRF}
254         ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8} ${VRF}
255
256         TMPFILE=$(mktemp /tmp/test_lwt_ip_encap.XXXXXX)
257
258         sleep 1  # reduce flakiness
259         set +e
260 }
261
262 cleanup()
263 {
264         if [ -f ${TMPFILE} ] ; then
265                 rm ${TMPFILE}
266         fi
267
268         ip netns del ${NS1} 2> /dev/null
269         ip netns del ${NS2} 2> /dev/null
270         ip netns del ${NS3} 2> /dev/null
271 }
272
273 trap cleanup EXIT
274
275 remove_routes_to_gredev()
276 {
277         ip -netns ${NS1} route del ${IPv4_GRE} dev veth5 ${VRF}
278         ip -netns ${NS2} route del ${IPv4_GRE} dev veth7 ${VRF}
279         ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5 ${VRF}
280         ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7 ${VRF}
281 }
282
283 add_unreachable_routes_to_gredev()
284 {
285         ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32 ${VRF}
286         ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32 ${VRF}
287         ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
288         ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
289 }
290
291 test_ping()
292 {
293         local readonly PROTO=$1
294         local readonly EXPECTED=$2
295         local RET=0
296
297         if [ "${PROTO}" == "IPv4" ] ; then
298                 ip netns exec ${NS1} ping  -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null
299                 RET=$?
300         elif [ "${PROTO}" == "IPv6" ] ; then
301                 ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/null
302                 RET=$?
303         else
304                 echo "    test_ping: unknown PROTO: ${PROTO}"
305                 TEST_STATUS=1
306         fi
307
308         if [ "0" != "${RET}" ]; then
309                 RET=1
310         fi
311
312         if [ "${EXPECTED}" != "${RET}" ] ; then
313                 echo "    test_ping failed: expected: ${EXPECTED}; got ${RET}"
314                 TEST_STATUS=1
315         fi
316 }
317
318 test_gso()
319 {
320         local readonly PROTO=$1
321         local readonly PKT_SZ=5000
322         local IP_DST=""
323         : > ${TMPFILE}  # trim the capture file
324
325         # check that nc is present
326         command -v nc >/dev/null 2>&1 || \
327                 { echo >&2 "nc is not available: skipping TSO tests"; return; }
328
329         # listen on port 9000, capture TCP into $TMPFILE
330         if [ "${PROTO}" == "IPv4" ] ; then
331                 IP_DST=${IPv4_DST}
332                 ip netns exec ${NS3} bash -c \
333                         "nc -4 -l -p 9000 > ${TMPFILE} &"
334         elif [ "${PROTO}" == "IPv6" ] ; then
335                 IP_DST=${IPv6_DST}
336                 ip netns exec ${NS3} bash -c \
337                         "nc -6 -l -p 9000 > ${TMPFILE} &"
338                 RET=$?
339         else
340                 echo "    test_gso: unknown PROTO: ${PROTO}"
341                 TEST_STATUS=1
342         fi
343         sleep 1  # let nc start listening
344
345         # send a packet larger than MTU
346         ip netns exec ${NS1} bash -c \
347                 "dd if=/dev/zero bs=$PKT_SZ count=1 > /dev/tcp/${IP_DST}/9000 2>/dev/null"
348         sleep 2 # let the packet get delivered
349
350         # verify we received all expected bytes
351         SZ=$(stat -c %s ${TMPFILE})
352         if [ "$SZ" != "$PKT_SZ" ] ; then
353                 echo "    test_gso failed: ${PROTO}"
354                 TEST_STATUS=1
355         fi
356 }
357
358 test_egress()
359 {
360         local readonly ENCAP=$1
361         echo "starting egress ${ENCAP} encap test ${VRF}"
362         setup
363
364         # by default, pings work
365         test_ping IPv4 0
366         test_ping IPv6 0
367
368         # remove NS2->DST routes, ping fails
369         ip -netns ${NS2}    route del ${IPv4_DST}/32  dev veth3 ${VRF}
370         ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
371         test_ping IPv4 1
372         test_ping IPv6 1
373
374         # install replacement routes (LWT/eBPF), pings succeed
375         if [ "${ENCAP}" == "IPv4" ] ; then
376                 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
377                         ${BPF_FILE} sec encap_gre dev veth1 ${VRF}
378                 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
379                         ${BPF_FILE} sec encap_gre dev veth1 ${VRF}
380         elif [ "${ENCAP}" == "IPv6" ] ; then
381                 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
382                         ${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}
383                 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
384                         ${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}
385         else
386                 echo "    unknown encap ${ENCAP}"
387                 TEST_STATUS=1
388         fi
389         test_ping IPv4 0
390         test_ping IPv6 0
391
392         # skip GSO tests with VRF: VRF routing needs properly assigned
393         # source IP/device, which is easy to do with ping and hard with dd/nc.
394         if [ -z "${VRF}" ] ; then
395                 test_gso IPv4
396                 test_gso IPv6
397         fi
398
399         # a negative test: remove routes to GRE devices: ping fails
400         remove_routes_to_gredev
401         test_ping IPv4 1
402         test_ping IPv6 1
403
404         # another negative test
405         add_unreachable_routes_to_gredev
406         test_ping IPv4 1
407         test_ping IPv6 1
408
409         cleanup
410         process_test_results
411 }
412
413 test_ingress()
414 {
415         local readonly ENCAP=$1
416         echo "starting ingress ${ENCAP} encap test ${VRF}"
417         setup
418
419         # need to wait a bit for IPv6 to autoconf, otherwise
420         # ping6 sometimes fails with "unable to bind to address"
421
422         # by default, pings work
423         test_ping IPv4 0
424         test_ping IPv6 0
425
426         # remove NS2->DST routes, pings fail
427         ip -netns ${NS2}    route del ${IPv4_DST}/32  dev veth3 ${VRF}
428         ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
429         test_ping IPv4 1
430         test_ping IPv6 1
431
432         # install replacement routes (LWT/eBPF), pings succeed
433         if [ "${ENCAP}" == "IPv4" ] ; then
434                 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
435                         ${BPF_FILE} sec encap_gre dev veth2 ${VRF}
436                 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
437                         ${BPF_FILE} sec encap_gre dev veth2 ${VRF}
438         elif [ "${ENCAP}" == "IPv6" ] ; then
439                 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
440                         ${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}
441                 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
442                         ${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}
443         else
444                 echo "FAIL: unknown encap ${ENCAP}"
445                 TEST_STATUS=1
446         fi
447         test_ping IPv4 0
448         test_ping IPv6 0
449
450         # a negative test: remove routes to GRE devices: ping fails
451         remove_routes_to_gredev
452         test_ping IPv4 1
453         test_ping IPv6 1
454
455         # another negative test
456         add_unreachable_routes_to_gredev
457         test_ping IPv4 1
458         test_ping IPv6 1
459
460         cleanup
461         process_test_results
462 }
463
464 VRF=""
465 test_egress IPv4
466 test_egress IPv6
467 test_ingress IPv4
468 test_ingress IPv6
469
470 VRF="vrf red"
471 test_egress IPv4
472 test_egress IPv6
473 test_ingress IPv4
474 test_ingress IPv6
475
476 print_test_summary_and_exit
This page took 0.059048 seconds and 4 git commands to generate.