blob: 612632c1425fc965ed15cae8a580153a25a1419d [file] [log] [blame]
Peter Oskolkov0fde56e2019-02-13 11:53:41 -08001#!/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
Peter Oskolkov0fde56e2019-02-13 11:53:41 -080041if [[ $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
Peter Oskolkov9d6b3582019-02-15 15:49:33 -080077TEST_STATUS=0
78TESTS_SUCCEEDED=0
79TESTS_FAILED=0
80
81process_test_results()
82{
83 if [[ "${TEST_STATUS}" -eq 0 ]] ; then
84 echo "PASS"
85 TESTS_SUCCEEDED=$((TESTS_SUCCEEDED+1))
86 else
87 echo "FAIL"
88 TESTS_FAILED=$((TESTS_FAILED+1))
89 fi
90}
91
92print_test_summary_and_exit()
93{
94 echo "passed tests: ${TESTS_SUCCEEDED}"
95 echo "failed tests: ${TESTS_FAILED}"
96 if [ "${TESTS_FAILED}" -eq "0" ] ; then
97 exit 0
98 else
99 exit 1
100 fi
101}
102
103setup()
104{
105 set -e # exit on error
106 TEST_STATUS=0
107
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800108 # create devices and namespaces
109 ip netns add "${NS1}"
110 ip netns add "${NS2}"
111 ip netns add "${NS3}"
112
113 ip link add veth1 type veth peer name veth2
114 ip link add veth3 type veth peer name veth4
115 ip link add veth5 type veth peer name veth6
116 ip link add veth7 type veth peer name veth8
117
118 ip netns exec ${NS2} sysctl -wq net.ipv4.ip_forward=1
119 ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.forwarding=1
120
121 ip link set veth1 netns ${NS1}
122 ip link set veth2 netns ${NS2}
123 ip link set veth3 netns ${NS2}
124 ip link set veth4 netns ${NS3}
125 ip link set veth5 netns ${NS1}
126 ip link set veth6 netns ${NS2}
127 ip link set veth7 netns ${NS2}
128 ip link set veth8 netns ${NS3}
129
130 # configure addesses: the top route (1-2-3-4)
131 ip -netns ${NS1} addr add ${IPv4_1}/24 dev veth1
132 ip -netns ${NS2} addr add ${IPv4_2}/24 dev veth2
133 ip -netns ${NS2} addr add ${IPv4_3}/24 dev veth3
134 ip -netns ${NS3} addr add ${IPv4_4}/24 dev veth4
135 ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1
136 ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2
137 ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3
138 ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4
139
140 # configure addresses: the bottom route (5-6-7-8)
141 ip -netns ${NS1} addr add ${IPv4_5}/24 dev veth5
142 ip -netns ${NS2} addr add ${IPv4_6}/24 dev veth6
143 ip -netns ${NS2} addr add ${IPv4_7}/24 dev veth7
144 ip -netns ${NS3} addr add ${IPv4_8}/24 dev veth8
145 ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5
146 ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6
147 ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7
148 ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8
149
150
151 ip -netns ${NS1} link set dev veth1 up
152 ip -netns ${NS2} link set dev veth2 up
153 ip -netns ${NS2} link set dev veth3 up
154 ip -netns ${NS3} link set dev veth4 up
155 ip -netns ${NS1} link set dev veth5 up
156 ip -netns ${NS2} link set dev veth6 up
157 ip -netns ${NS2} link set dev veth7 up
158 ip -netns ${NS3} link set dev veth8 up
159
160 # configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;
161 # the bottom route to specific bottom addresses
162
163 # NS1
164 # top route
165 ip -netns ${NS1} route add ${IPv4_2}/32 dev veth1
166 ip -netns ${NS1} route add default dev veth1 via ${IPv4_2} # go top by default
167 ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1
168 ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} # go top by default
169 # bottom route
170 ip -netns ${NS1} route add ${IPv4_6}/32 dev veth5
171 ip -netns ${NS1} route add ${IPv4_7}/32 dev veth5 via ${IPv4_6}
172 ip -netns ${NS1} route add ${IPv4_8}/32 dev veth5 via ${IPv4_6}
173 ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5
174 ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6}
175 ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6}
176
177 # NS2
178 # top route
179 ip -netns ${NS2} route add ${IPv4_1}/32 dev veth2
180 ip -netns ${NS2} route add ${IPv4_4}/32 dev veth3
181 ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2
182 ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3
183 # bottom route
184 ip -netns ${NS2} route add ${IPv4_5}/32 dev veth6
185 ip -netns ${NS2} route add ${IPv4_8}/32 dev veth7
186 ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6
187 ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7
188
189 # NS3
190 # top route
191 ip -netns ${NS3} route add ${IPv4_3}/32 dev veth4
192 ip -netns ${NS3} route add ${IPv4_1}/32 dev veth4 via ${IPv4_3}
193 ip -netns ${NS3} route add ${IPv4_2}/32 dev veth4 via ${IPv4_3}
194 ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4
195 ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}
196 ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}
197 # bottom route
198 ip -netns ${NS3} route add ${IPv4_7}/32 dev veth8
199 ip -netns ${NS3} route add ${IPv4_5}/32 dev veth8 via ${IPv4_7}
200 ip -netns ${NS3} route add ${IPv4_6}/32 dev veth8 via ${IPv4_7}
201 ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8
202 ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}
203 ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}
204
205 # configure IPv4 GRE device in NS3, and a route to it via the "bottom" route
206 ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255
207 ip -netns ${NS3} link set gre_dev up
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800208 ip -netns ${NS3} addr add ${IPv4_GRE} nodad dev gre_dev
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800209 ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6}
210 ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8}
211
212
213 # configure IPv6 GRE device in NS3, and a route to it via the "bottom" route
214 ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255
215 ip -netns ${NS3} link set gre6_dev up
216 ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev
217 ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6}
218 ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8}
219
220 # rp_filter gets confused by what these tests are doing, so disable it
221 ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0
222 ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0
223 ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800224
225 sleep 1 # reduce flakiness
226 set +e
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800227}
228
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800229cleanup()
230{
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800231 ip netns del ${NS1} 2> /dev/null
232 ip netns del ${NS2} 2> /dev/null
233 ip netns del ${NS3} 2> /dev/null
234}
235
236trap cleanup EXIT
237
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800238remove_routes_to_gredev()
239{
240 ip -netns ${NS1} route del ${IPv4_GRE} dev veth5
241 ip -netns ${NS2} route del ${IPv4_GRE} dev veth7
242 ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5
243 ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7
244}
245
246add_unreachable_routes_to_gredev()
247{
248 ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32
249 ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32
250 ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128
251 ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128
252}
253
254test_ping()
255{
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800256 local readonly PROTO=$1
257 local readonly EXPECTED=$2
258 local RET=0
259
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800260 if [ "${PROTO}" == "IPv4" ] ; then
261 ip netns exec ${NS1} ping -c 1 -W 1 -I ${IPv4_SRC} ${IPv4_DST} 2>&1 > /dev/null
262 RET=$?
263 elif [ "${PROTO}" == "IPv6" ] ; then
264 ip netns exec ${NS1} ping6 -c 1 -W 6 -I ${IPv6_SRC} ${IPv6_DST} 2>&1 > /dev/null
265 RET=$?
266 else
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800267 echo " test_ping: unknown PROTO: ${PROTO}"
268 TEST_STATUS=1
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800269 fi
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800270
271 if [ "0" != "${RET}" ]; then
272 RET=1
273 fi
274
275 if [ "${EXPECTED}" != "${RET}" ] ; then
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800276 echo " test_ping failed: expected: ${EXPECTED}; got ${RET}"
277 TEST_STATUS=1
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800278 fi
279}
280
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800281test_egress()
282{
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800283 local readonly ENCAP=$1
284 echo "starting egress ${ENCAP} encap test"
285 setup
286
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800287 # by default, pings work
288 test_ping IPv4 0
289 test_ping IPv6 0
290
291 # remove NS2->DST routes, ping fails
292 ip -netns ${NS2} route del ${IPv4_DST}/32 dev veth3
293 ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3
294 test_ping IPv4 1
295 test_ping IPv6 1
296
297 # install replacement routes (LWT/eBPF), pings succeed
298 if [ "${ENCAP}" == "IPv4" ] ; then
299 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre dev veth1
300 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre dev veth1
301 elif [ "${ENCAP}" == "IPv6" ] ; then
302 ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre6 dev veth1
303 ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj test_lwt_ip_encap.o sec encap_gre6 dev veth1
304 else
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800305 echo " unknown encap ${ENCAP}"
306 TEST_STATUS=1
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800307 fi
308 test_ping IPv4 0
309 test_ping IPv6 0
310
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800311 # a negative test: remove routes to GRE devices: ping fails
312 remove_routes_to_gredev
313 test_ping IPv4 1
314 test_ping IPv6 1
315
316 # another negative test
317 add_unreachable_routes_to_gredev
318 test_ping IPv4 1
319 test_ping IPv6 1
320
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800321 cleanup
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800322 process_test_results
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800323}
324
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800325test_ingress()
326{
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800327 local readonly ENCAP=$1
328 echo "starting ingress ${ENCAP} encap test"
329 setup
330
331 # need to wait a bit for IPv6 to autoconf, otherwise
332 # ping6 sometimes fails with "unable to bind to address"
333
334 # by default, pings work
335 test_ping IPv4 0
336 test_ping IPv6 0
337
338 # remove NS2->DST routes, pings fail
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 ${NS2} route add ${IPv4_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre dev veth2
347 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre dev veth2
348 elif [ "${ENCAP}" == "IPv6" ] ; then
349 ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre6 dev veth2
350 ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj test_lwt_ip_encap.o sec encap_gre6 dev veth2
351 else
352 echo "FAIL: unknown encap ${ENCAP}"
353 fi
354 test_ping IPv4 0
355 test_ping IPv6 0
356
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800357 # a negative test: remove routes to GRE devices: ping fails
358 remove_routes_to_gredev
359 test_ping IPv4 1
360 test_ping IPv6 1
361
362 # another negative test
363 add_unreachable_routes_to_gredev
364 test_ping IPv4 1
365 test_ping IPv6 1
366
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800367 cleanup
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800368 process_test_results
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800369}
370
371test_egress IPv4
372test_egress IPv6
Peter Oskolkov0fde56e2019-02-13 11:53:41 -0800373test_ingress IPv4
374test_ingress IPv6
375
Peter Oskolkov9d6b3582019-02-15 15:49:33 -0800376print_test_summary_and_exit