WIP FPC-III support
[linux/fpc-iii.git] / tools / testing / selftests / bpf / test_lwt_ip_encap.sh
blob59ea56945e6cd6819dc12fe337f324d784449e48
1 #!/bin/bash
2 # SPDX-License-Identifier: GPL-2.0
4 # Setup/topology:
6 # NS1 NS2 NS3
7 # veth1 <---> veth2 veth3 <---> veth4 (the top route)
8 # veth5 <---> veth6 veth7 <---> veth8 (the bottom route)
10 # each vethN gets IPv[4|6]_N address
12 # IPv*_SRC = IPv*_1
13 # IPv*_DST = IPv*_4
15 # all tests test pings from IPv*_SRC to IPv*_DST
17 # by default, routes are configured to allow packets to go
18 # IP*_1 <=> IP*_2 <=> IP*_3 <=> IP*_4 (the top route)
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)
24 # Tests:
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
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
32 # ping: SRC->[encap at veth1:egress]->GRE:decap->DST
33 # ping replies go DST->SRC directly
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
38 # ping: SRC->[encap at veth2:ingress]->GRE:decap->DST
39 # ping replies go DST->SRC directly
41 if [[ $EUID -ne 0 ]]; then
42 echo "This script must be run as root"
43 echo "FAIL"
44 exit 1
47 readonly NS1="ns1-$(mktemp -u XXXXXX)"
48 readonly NS2="ns2-$(mktemp -u XXXXXX)"
49 readonly NS3="ns3-$(mktemp -u XXXXXX)"
51 readonly IPv4_1="172.16.1.100"
52 readonly IPv4_2="172.16.2.100"
53 readonly IPv4_3="172.16.3.100"
54 readonly IPv4_4="172.16.4.100"
55 readonly IPv4_5="172.16.5.100"
56 readonly IPv4_6="172.16.6.100"
57 readonly IPv4_7="172.16.7.100"
58 readonly IPv4_8="172.16.8.100"
59 readonly IPv4_GRE="172.16.16.100"
61 readonly IPv4_SRC=$IPv4_1
62 readonly IPv4_DST=$IPv4_4
64 readonly IPv6_1="fb01::1"
65 readonly IPv6_2="fb02::1"
66 readonly IPv6_3="fb03::1"
67 readonly IPv6_4="fb04::1"
68 readonly IPv6_5="fb05::1"
69 readonly IPv6_6="fb06::1"
70 readonly IPv6_7="fb07::1"
71 readonly IPv6_8="fb08::1"
72 readonly IPv6_GRE="fb10::1"
74 readonly IPv6_SRC=$IPv6_1
75 readonly IPv6_DST=$IPv6_4
77 TEST_STATUS=0
78 TESTS_SUCCEEDED=0
79 TESTS_FAILED=0
81 TMPFILE=""
83 process_test_results()
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))
94 print_test_summary_and_exit()
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
105 setup()
107 set -e # exit on error
108 TEST_STATUS=0
110 # create devices and namespaces
111 ip netns add "${NS1}"
112 ip netns add "${NS2}"
113 ip netns add "${NS3}"
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
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
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}
132 if [ ! -z "${VRF}" ] ; then
133 ip -netns ${NS1} link add red type vrf table 1001
134 ip -netns ${NS1} link set red up
135 ip -netns ${NS1} route add table 1001 unreachable default metric 8192
136 ip -netns ${NS1} -6 route add table 1001 unreachable default metric 8192
137 ip -netns ${NS1} link set veth1 vrf red
138 ip -netns ${NS1} link set veth5 vrf red
140 ip -netns ${NS2} link add red type vrf table 1001
141 ip -netns ${NS2} link set red up
142 ip -netns ${NS2} route add table 1001 unreachable default metric 8192
143 ip -netns ${NS2} -6 route add table 1001 unreachable default metric 8192
144 ip -netns ${NS2} link set veth2 vrf red
145 ip -netns ${NS2} link set veth3 vrf red
146 ip -netns ${NS2} link set veth6 vrf red
147 ip -netns ${NS2} link set veth7 vrf red
150 # configure addesses: the top route (1-2-3-4)
151 ip -netns ${NS1} addr add ${IPv4_1}/24 dev veth1
152 ip -netns ${NS2} addr add ${IPv4_2}/24 dev veth2
153 ip -netns ${NS2} addr add ${IPv4_3}/24 dev veth3
154 ip -netns ${NS3} addr add ${IPv4_4}/24 dev veth4
155 ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1
156 ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2
157 ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3
158 ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4
160 # configure addresses: the bottom route (5-6-7-8)
161 ip -netns ${NS1} addr add ${IPv4_5}/24 dev veth5
162 ip -netns ${NS2} addr add ${IPv4_6}/24 dev veth6
163 ip -netns ${NS2} addr add ${IPv4_7}/24 dev veth7
164 ip -netns ${NS3} addr add ${IPv4_8}/24 dev veth8
165 ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5
166 ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6
167 ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7
168 ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8
170 ip -netns ${NS1} link set dev veth1 up
171 ip -netns ${NS2} link set dev veth2 up
172 ip -netns ${NS2} link set dev veth3 up
173 ip -netns ${NS3} link set dev veth4 up
174 ip -netns ${NS1} link set dev veth5 up
175 ip -netns ${NS2} link set dev veth6 up
176 ip -netns ${NS2} link set dev veth7 up
177 ip -netns ${NS3} link set dev veth8 up
179 # configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;
180 # the bottom route to specific bottom addresses
182 # NS1
183 # top route
184 ip -netns ${NS1} route add ${IPv4_2}/32 dev veth1 ${VRF}
185 ip -netns ${NS1} route add default dev veth1 via ${IPv4_2} ${VRF} # go top by default
186 ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1 ${VRF}
187 ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} ${VRF} # go top by default
188 # bottom route
189 ip -netns ${NS1} route add ${IPv4_6}/32 dev veth5 ${VRF}
190 ip -netns ${NS1} route add ${IPv4_7}/32 dev veth5 via ${IPv4_6} ${VRF}
191 ip -netns ${NS1} route add ${IPv4_8}/32 dev veth5 via ${IPv4_6} ${VRF}
192 ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5 ${VRF}
193 ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6} ${VRF}
194 ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6} ${VRF}
196 # NS2
197 # top route
198 ip -netns ${NS2} route add ${IPv4_1}/32 dev veth2 ${VRF}
199 ip -netns ${NS2} route add ${IPv4_4}/32 dev veth3 ${VRF}
200 ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2 ${VRF}
201 ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3 ${VRF}
202 # bottom route
203 ip -netns ${NS2} route add ${IPv4_5}/32 dev veth6 ${VRF}
204 ip -netns ${NS2} route add ${IPv4_8}/32 dev veth7 ${VRF}
205 ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6 ${VRF}
206 ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7 ${VRF}
208 # NS3
209 # top route
210 ip -netns ${NS3} route add ${IPv4_3}/32 dev veth4
211 ip -netns ${NS3} route add ${IPv4_1}/32 dev veth4 via ${IPv4_3}
212 ip -netns ${NS3} route add ${IPv4_2}/32 dev veth4 via ${IPv4_3}
213 ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4
214 ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}
215 ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}
216 # bottom route
217 ip -netns ${NS3} route add ${IPv4_7}/32 dev veth8
218 ip -netns ${NS3} route add ${IPv4_5}/32 dev veth8 via ${IPv4_7}
219 ip -netns ${NS3} route add ${IPv4_6}/32 dev veth8 via ${IPv4_7}
220 ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8
221 ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}
222 ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}
224 # configure IPv4 GRE device in NS3, and a route to it via the "bottom" route
225 ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255
226 ip -netns ${NS3} link set gre_dev up
227 ip -netns ${NS3} addr add ${IPv4_GRE} dev gre_dev
228 ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6} ${VRF}
229 ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8} ${VRF}
232 # configure IPv6 GRE device in NS3, and a route to it via the "bottom" route
233 ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255
234 ip -netns ${NS3} link set gre6_dev up
235 ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev
236 ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6} ${VRF}
237 ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8} ${VRF}
239 # rp_filter gets confused by what these tests are doing, so disable it
240 ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0
241 ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0
242 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0
244 TMPFILE=$(mktemp /tmp/test_lwt_ip_encap.XXXXXX)
246 sleep 1 # reduce flakiness
247 set +e
250 cleanup()
252 if [ -f ${TMPFILE} ] ; then
253 rm ${TMPFILE}
256 ip netns del ${NS1} 2> /dev/null
257 ip netns del ${NS2} 2> /dev/null
258 ip netns del ${NS3} 2> /dev/null
261 trap cleanup EXIT
263 remove_routes_to_gredev()
265 ip -netns ${NS1} route del ${IPv4_GRE} dev veth5 ${VRF}
266 ip -netns ${NS2} route del ${IPv4_GRE} dev veth7 ${VRF}
267 ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5 ${VRF}
268 ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7 ${VRF}
271 add_unreachable_routes_to_gredev()
273 ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32 ${VRF}
274 ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32 ${VRF}
275 ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
276 ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}
279 test_ping()
281 local readonly PROTO=$1
282 local readonly EXPECTED=$2
283 local RET=0
285 if [ "${PROTO}" == "IPv4" ] ; then
286 ip netns exec ${NS1} ping -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null
287 RET=$?
288 elif [ "${PROTO}" == "IPv6" ] ; then
289 ip netns exec ${NS1} ping6 -c 1 -W 6 -I veth1 ${IPv6_DST} 2>&1 > /dev/null
290 RET=$?
291 else
292 echo " test_ping: unknown PROTO: ${PROTO}"
293 TEST_STATUS=1
296 if [ "0" != "${RET}" ]; then
297 RET=1
300 if [ "${EXPECTED}" != "${RET}" ] ; then
301 echo " test_ping failed: expected: ${EXPECTED}; got ${RET}"
302 TEST_STATUS=1
306 test_gso()
308 local readonly PROTO=$1
309 local readonly PKT_SZ=5000
310 local IP_DST=""
311 : > ${TMPFILE} # trim the capture file
313 # check that nc is present
314 command -v nc >/dev/null 2>&1 || \
315 { echo >&2 "nc is not available: skipping TSO tests"; return; }
317 # listen on port 9000, capture TCP into $TMPFILE
318 if [ "${PROTO}" == "IPv4" ] ; then
319 IP_DST=${IPv4_DST}
320 ip netns exec ${NS3} bash -c \
321 "nc -4 -l -p 9000 > ${TMPFILE} &"
322 elif [ "${PROTO}" == "IPv6" ] ; then
323 IP_DST=${IPv6_DST}
324 ip netns exec ${NS3} bash -c \
325 "nc -6 -l -p 9000 > ${TMPFILE} &"
326 RET=$?
327 else
328 echo " test_gso: unknown PROTO: ${PROTO}"
329 TEST_STATUS=1
331 sleep 1 # let nc start listening
333 # send a packet larger than MTU
334 ip netns exec ${NS1} bash -c \
335 "dd if=/dev/zero bs=$PKT_SZ count=1 > /dev/tcp/${IP_DST}/9000 2>/dev/null"
336 sleep 2 # let the packet get delivered
338 # verify we received all expected bytes
339 SZ=$(stat -c %s ${TMPFILE})
340 if [ "$SZ" != "$PKT_SZ" ] ; then
341 echo " test_gso failed: ${PROTO}"
342 TEST_STATUS=1
346 test_egress()
348 local readonly ENCAP=$1
349 echo "starting egress ${ENCAP} encap test ${VRF}"
350 setup
352 # by default, pings work
353 test_ping IPv4 0
354 test_ping IPv6 0
356 # remove NS2->DST routes, ping fails
357 ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3 ${VRF}
358 ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
359 test_ping IPv4 1
360 test_ping IPv6 1
362 # install replacement routes (LWT/eBPF), pings succeed
363 if [ "${ENCAP}" == "IPv4" ] ; then
364 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
365 test_lwt_ip_encap.o sec encap_gre dev veth1 ${VRF}
366 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
367 test_lwt_ip_encap.o sec encap_gre dev veth1 ${VRF}
368 elif [ "${ENCAP}" == "IPv6" ] ; then
369 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \
370 test_lwt_ip_encap.o sec encap_gre6 dev veth1 ${VRF}
371 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \
372 test_lwt_ip_encap.o sec encap_gre6 dev veth1 ${VRF}
373 else
374 echo " unknown encap ${ENCAP}"
375 TEST_STATUS=1
377 test_ping IPv4 0
378 test_ping IPv6 0
380 # skip GSO tests with VRF: VRF routing needs properly assigned
381 # source IP/device, which is easy to do with ping and hard with dd/nc.
382 if [ -z "${VRF}" ] ; then
383 test_gso IPv4
384 test_gso IPv6
387 # a negative test: remove routes to GRE devices: ping fails
388 remove_routes_to_gredev
389 test_ping IPv4 1
390 test_ping IPv6 1
392 # another negative test
393 add_unreachable_routes_to_gredev
394 test_ping IPv4 1
395 test_ping IPv6 1
397 cleanup
398 process_test_results
401 test_ingress()
403 local readonly ENCAP=$1
404 echo "starting ingress ${ENCAP} encap test ${VRF}"
405 setup
407 # need to wait a bit for IPv6 to autoconf, otherwise
408 # ping6 sometimes fails with "unable to bind to address"
410 # by default, pings work
411 test_ping IPv4 0
412 test_ping IPv6 0
414 # remove NS2->DST routes, pings fail
415 ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3 ${VRF}
416 ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}
417 test_ping IPv4 1
418 test_ping IPv6 1
420 # install replacement routes (LWT/eBPF), pings succeed
421 if [ "${ENCAP}" == "IPv4" ] ; then
422 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
423 test_lwt_ip_encap.o sec encap_gre dev veth2 ${VRF}
424 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
425 test_lwt_ip_encap.o sec encap_gre dev veth2 ${VRF}
426 elif [ "${ENCAP}" == "IPv6" ] ; then
427 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \
428 test_lwt_ip_encap.o sec encap_gre6 dev veth2 ${VRF}
429 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \
430 test_lwt_ip_encap.o sec encap_gre6 dev veth2 ${VRF}
431 else
432 echo "FAIL: unknown encap ${ENCAP}"
433 TEST_STATUS=1
435 test_ping IPv4 0
436 test_ping IPv6 0
438 # a negative test: remove routes to GRE devices: ping fails
439 remove_routes_to_gredev
440 test_ping IPv4 1
441 test_ping IPv6 1
443 # another negative test
444 add_unreachable_routes_to_gredev
445 test_ping IPv4 1
446 test_ping IPv6 1
448 cleanup
449 process_test_results
452 VRF=""
453 test_egress IPv4
454 test_egress IPv6
455 test_ingress IPv4
456 test_ingress IPv6
458 VRF="vrf red"
459 test_egress IPv4
460 test_egress IPv6
461 test_ingress IPv4
462 test_ingress IPv6
464 print_test_summary_and_exit