1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# End-to-end eBPF tunnel test suite
5#   The script tests BPF network tunnel implementation.
6#
7# Topology:
8# ---------
9#     root namespace   |     at_ns0 namespace
10#                      |
11#      -----------     |     -----------
12#      | tnl dev |     |     | tnl dev |  (overlay network)
13#      -----------     |     -----------
14#      metadata-mode   |     native-mode
15#       with bpf       |
16#                      |
17#      ----------      |     ----------
18#      |  veth1  | --------- |  veth0  |  (underlay network)
19#      ----------    peer    ----------
20#
21#
22# Device Configuration
23# --------------------
24# Root namespace with metadata-mode tunnel + BPF
25# Device names and addresses:
26# 	veth1 IP: 172.16.1.200, IPv6: 00::22 (underlay)
27# 	tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay)
28#
29# Namespace at_ns0 with native tunnel
30# Device names and addresses:
31# 	veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay)
32# 	tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay)
33#
34#
35# End-to-end ping packet flow
36# ---------------------------
37# Most of the tests start by namespace creation, device configuration,
38# then ping the underlay and overlay network.  When doing 'ping 10.1.1.100'
39# from root namespace, the following operations happen:
40# 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev.
41# 2) Tnl device's egress BPF program is triggered and set the tunnel metadata,
42#    with remote_ip=172.16.1.100 and others.
43# 3) Outer tunnel header is prepended and route the packet to veth1's egress
44# 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0
45# 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet
46# 6) Forward the packet to the overlay tnl dev
47
48BPF_FILE="test_tunnel_kern.bpf.o"
49BPF_PIN_TUNNEL_DIR="/sys/fs/bpf/tc/tunnel"
50PING_ARG="-c 3 -w 10 -q"
51ret=0
52GREEN='\033[0;92m'
53RED='\033[0;31m'
54NC='\033[0m' # No Color
55
56config_device()
57{
58	ip netns add at_ns0
59	ip link add veth0 type veth peer name veth1
60	ip link set veth0 netns at_ns0
61	ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0
62	ip netns exec at_ns0 ip link set dev veth0 up
63	ip link set dev veth1 up mtu 1500
64	ip addr add dev veth1 172.16.1.200/24
65}
66
67add_gre_tunnel()
68{
69	tun_key=
70	if [ -n "$1" ]; then
71		tun_key="key $1"
72	fi
73
74	# at_ns0 namespace
75	ip netns exec at_ns0 \
76        ip link add dev $DEV_NS type $TYPE seq $tun_key \
77		local 172.16.1.100 remote 172.16.1.200
78	ip netns exec at_ns0 ip link set dev $DEV_NS up
79	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
80
81	# root namespace
82	ip link add dev $DEV type $TYPE $tun_key external
83	ip link set dev $DEV up
84	ip addr add dev $DEV 10.1.1.200/24
85}
86
87add_ip6gretap_tunnel()
88{
89
90	# assign ipv6 address
91	ip netns exec at_ns0 ip addr add ::11/96 dev veth0
92	ip netns exec at_ns0 ip link set dev veth0 up
93	ip addr add dev veth1 ::22/96
94	ip link set dev veth1 up
95
96	# at_ns0 namespace
97	ip netns exec at_ns0 \
98		ip link add dev $DEV_NS type $TYPE seq flowlabel 0xbcdef key 2 \
99		local ::11 remote ::22
100
101	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
102	ip netns exec at_ns0 ip addr add dev $DEV_NS fc80::100/96
103	ip netns exec at_ns0 ip link set dev $DEV_NS up
104
105	# root namespace
106	ip link add dev $DEV type $TYPE external
107	ip addr add dev $DEV 10.1.1.200/24
108	ip addr add dev $DEV fc80::200/24
109	ip link set dev $DEV up
110}
111
112add_erspan_tunnel()
113{
114	# at_ns0 namespace
115	if [ "$1" == "v1" ]; then
116		ip netns exec at_ns0 \
117		ip link add dev $DEV_NS type $TYPE seq key 2 \
118		local 172.16.1.100 remote 172.16.1.200 \
119		erspan_ver 1 erspan 123
120	else
121		ip netns exec at_ns0 \
122		ip link add dev $DEV_NS type $TYPE seq key 2 \
123		local 172.16.1.100 remote 172.16.1.200 \
124		erspan_ver 2 erspan_dir egress erspan_hwid 3
125	fi
126	ip netns exec at_ns0 ip link set dev $DEV_NS up
127	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
128
129	# root namespace
130	ip link add dev $DEV type $TYPE external
131	ip link set dev $DEV up
132	ip addr add dev $DEV 10.1.1.200/24
133}
134
135add_ip6erspan_tunnel()
136{
137
138	# assign ipv6 address
139	ip netns exec at_ns0 ip addr add ::11/96 dev veth0
140	ip netns exec at_ns0 ip link set dev veth0 up
141	ip addr add dev veth1 ::22/96
142	ip link set dev veth1 up
143
144	# at_ns0 namespace
145	if [ "$1" == "v1" ]; then
146		ip netns exec at_ns0 \
147		ip link add dev $DEV_NS type $TYPE seq key 2 \
148		local ::11 remote ::22 \
149		erspan_ver 1 erspan 123
150	else
151		ip netns exec at_ns0 \
152		ip link add dev $DEV_NS type $TYPE seq key 2 \
153		local ::11 remote ::22 \
154		erspan_ver 2 erspan_dir egress erspan_hwid 7
155	fi
156	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
157	ip netns exec at_ns0 ip link set dev $DEV_NS up
158
159	# root namespace
160	ip link add dev $DEV type $TYPE external
161	ip addr add dev $DEV 10.1.1.200/24
162	ip link set dev $DEV up
163}
164
165add_geneve_tunnel()
166{
167	# at_ns0 namespace
168	ip netns exec at_ns0 \
169		ip link add dev $DEV_NS type $TYPE \
170		id 2 dstport 6081 remote 172.16.1.200
171	ip netns exec at_ns0 ip link set dev $DEV_NS up
172	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
173
174	# root namespace
175	ip link add dev $DEV type $TYPE dstport 6081 external
176	ip link set dev $DEV up
177	ip addr add dev $DEV 10.1.1.200/24
178}
179
180add_ip6geneve_tunnel()
181{
182	ip netns exec at_ns0 ip addr add ::11/96 dev veth0
183	ip netns exec at_ns0 ip link set dev veth0 up
184	ip addr add dev veth1 ::22/96
185	ip link set dev veth1 up
186
187	# at_ns0 namespace
188	ip netns exec at_ns0 \
189		ip link add dev $DEV_NS type $TYPE id 22 \
190		remote ::22     # geneve has no local option
191	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
192	ip netns exec at_ns0 ip link set dev $DEV_NS up
193
194	# root namespace
195	ip link add dev $DEV type $TYPE external
196	ip addr add dev $DEV 10.1.1.200/24
197	ip link set dev $DEV up
198}
199
200add_ipip_tunnel()
201{
202	# at_ns0 namespace
203	ip netns exec at_ns0 \
204		ip link add dev $DEV_NS type $TYPE \
205		local 172.16.1.100 remote 172.16.1.200
206	ip netns exec at_ns0 ip link set dev $DEV_NS up
207	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
208
209	# root namespace
210	ip link add dev $DEV type $TYPE external
211	ip link set dev $DEV up
212	ip addr add dev $DEV 10.1.1.200/24
213}
214
215add_ip6tnl_tunnel()
216{
217	ip netns exec at_ns0 ip addr add ::11/96 dev veth0
218	ip netns exec at_ns0 ip link set dev veth0 up
219	ip addr add dev veth1 ::22/96
220	ip link set dev veth1 up
221
222	# at_ns0 namespace
223	ip netns exec at_ns0 \
224		ip link add dev $DEV_NS type $TYPE \
225		local ::11 remote ::22
226	ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24
227	ip netns exec at_ns0 ip addr add dev $DEV_NS 1::11/96
228	ip netns exec at_ns0 ip link set dev $DEV_NS up
229
230	# root namespace
231	ip link add dev $DEV type $TYPE external
232	ip addr add dev $DEV 10.1.1.200/24
233	ip addr add dev $DEV 1::22/96
234	ip link set dev $DEV up
235}
236
237test_gre()
238{
239	TYPE=gretap
240	DEV_NS=gretap00
241	DEV=gretap11
242	ret=0
243
244	check $TYPE
245	config_device
246	add_gre_tunnel 2
247	attach_bpf $DEV gre_set_tunnel gre_get_tunnel
248	ping $PING_ARG 10.1.1.100
249	check_err $?
250	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
251	check_err $?
252	cleanup
253
254        if [ $ret -ne 0 ]; then
255                echo -e ${RED}"FAIL: $TYPE"${NC}
256                return 1
257        fi
258        echo -e ${GREEN}"PASS: $TYPE"${NC}
259}
260
261test_gre_no_tunnel_key()
262{
263	TYPE=gre
264	DEV_NS=gre00
265	DEV=gre11
266	ret=0
267
268	check $TYPE
269	config_device
270	add_gre_tunnel
271	attach_bpf $DEV gre_set_tunnel_no_key gre_get_tunnel
272	ping $PING_ARG 10.1.1.100
273	check_err $?
274	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
275	check_err $?
276	cleanup
277
278        if [ $ret -ne 0 ]; then
279                echo -e ${RED}"FAIL: $TYPE"${NC}
280                return 1
281        fi
282        echo -e ${GREEN}"PASS: $TYPE"${NC}
283}
284
285test_ip6gre()
286{
287	TYPE=ip6gre
288	DEV_NS=ip6gre00
289	DEV=ip6gre11
290	ret=0
291
292	check $TYPE
293	config_device
294	# reuse the ip6gretap function
295	add_ip6gretap_tunnel
296	attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
297	# underlay
298	ping6 $PING_ARG ::11
299	# overlay: ipv4 over ipv6
300	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
301	ping $PING_ARG 10.1.1.100
302	check_err $?
303	# overlay: ipv6 over ipv6
304	ip netns exec at_ns0 ping6 $PING_ARG fc80::200
305	check_err $?
306	cleanup
307
308        if [ $ret -ne 0 ]; then
309                echo -e ${RED}"FAIL: $TYPE"${NC}
310                return 1
311        fi
312        echo -e ${GREEN}"PASS: $TYPE"${NC}
313}
314
315test_ip6gretap()
316{
317	TYPE=ip6gretap
318	DEV_NS=ip6gretap00
319	DEV=ip6gretap11
320	ret=0
321
322	check $TYPE
323	config_device
324	add_ip6gretap_tunnel
325	attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel
326	# underlay
327	ping6 $PING_ARG ::11
328	# overlay: ipv4 over ipv6
329	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
330	ping $PING_ARG 10.1.1.100
331	check_err $?
332	# overlay: ipv6 over ipv6
333	ip netns exec at_ns0 ping6 $PING_ARG fc80::200
334	check_err $?
335	cleanup
336
337	if [ $ret -ne 0 ]; then
338                echo -e ${RED}"FAIL: $TYPE"${NC}
339                return 1
340        fi
341        echo -e ${GREEN}"PASS: $TYPE"${NC}
342}
343
344test_erspan()
345{
346	TYPE=erspan
347	DEV_NS=erspan00
348	DEV=erspan11
349	ret=0
350
351	check $TYPE
352	config_device
353	add_erspan_tunnel $1
354	attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel
355	ping $PING_ARG 10.1.1.100
356	check_err $?
357	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
358	check_err $?
359	cleanup
360
361	if [ $ret -ne 0 ]; then
362                echo -e ${RED}"FAIL: $TYPE"${NC}
363                return 1
364        fi
365        echo -e ${GREEN}"PASS: $TYPE"${NC}
366}
367
368test_ip6erspan()
369{
370	TYPE=ip6erspan
371	DEV_NS=ip6erspan00
372	DEV=ip6erspan11
373	ret=0
374
375	check $TYPE
376	config_device
377	add_ip6erspan_tunnel $1
378	attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel
379	ping6 $PING_ARG ::11
380	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
381	check_err $?
382	cleanup
383
384	if [ $ret -ne 0 ]; then
385                echo -e ${RED}"FAIL: $TYPE"${NC}
386                return 1
387        fi
388        echo -e ${GREEN}"PASS: $TYPE"${NC}
389}
390
391test_geneve()
392{
393	TYPE=geneve
394	DEV_NS=geneve00
395	DEV=geneve11
396	ret=0
397
398	check $TYPE
399	config_device
400	add_geneve_tunnel
401	attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel
402	ping $PING_ARG 10.1.1.100
403	check_err $?
404	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
405	check_err $?
406	cleanup
407
408	if [ $ret -ne 0 ]; then
409                echo -e ${RED}"FAIL: $TYPE"${NC}
410                return 1
411        fi
412        echo -e ${GREEN}"PASS: $TYPE"${NC}
413}
414
415test_ip6geneve()
416{
417	TYPE=geneve
418	DEV_NS=ip6geneve00
419	DEV=ip6geneve11
420	ret=0
421
422	check $TYPE
423	config_device
424	add_ip6geneve_tunnel
425	attach_bpf $DEV ip6geneve_set_tunnel ip6geneve_get_tunnel
426	ping $PING_ARG 10.1.1.100
427	check_err $?
428	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
429	check_err $?
430	cleanup
431
432	if [ $ret -ne 0 ]; then
433                echo -e ${RED}"FAIL: ip6$TYPE"${NC}
434                return 1
435        fi
436        echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
437}
438
439test_ipip()
440{
441	TYPE=ipip
442	DEV_NS=ipip00
443	DEV=ipip11
444	ret=0
445
446	check $TYPE
447	config_device
448	add_ipip_tunnel
449	ip link set dev veth1 mtu 1500
450	attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel
451	ping $PING_ARG 10.1.1.100
452	check_err $?
453	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
454	check_err $?
455	cleanup
456
457	if [ $ret -ne 0 ]; then
458                echo -e ${RED}"FAIL: $TYPE"${NC}
459                return 1
460        fi
461        echo -e ${GREEN}"PASS: $TYPE"${NC}
462}
463
464test_ipip6()
465{
466	TYPE=ip6tnl
467	DEV_NS=ipip6tnl00
468	DEV=ipip6tnl11
469	ret=0
470
471	check $TYPE
472	config_device
473	add_ip6tnl_tunnel
474	ip link set dev veth1 mtu 1500
475	attach_bpf $DEV ipip6_set_tunnel ipip6_get_tunnel
476	# underlay
477	ping6 $PING_ARG ::11
478	# ip4 over ip6
479	ping $PING_ARG 10.1.1.100
480	check_err $?
481	ip netns exec at_ns0 ping $PING_ARG 10.1.1.200
482	check_err $?
483	cleanup
484
485	if [ $ret -ne 0 ]; then
486                echo -e ${RED}"FAIL: $TYPE"${NC}
487                return 1
488        fi
489        echo -e ${GREEN}"PASS: $TYPE"${NC}
490}
491
492test_ip6ip6()
493{
494	TYPE=ip6tnl
495	DEV_NS=ip6ip6tnl00
496	DEV=ip6ip6tnl11
497	ret=0
498
499	check $TYPE
500	config_device
501	add_ip6tnl_tunnel
502	ip link set dev veth1 mtu 1500
503	attach_bpf $DEV ip6ip6_set_tunnel ip6ip6_get_tunnel
504	# underlay
505	ping6 $PING_ARG ::11
506	# ip6 over ip6
507	ping6 $PING_ARG 1::11
508	check_err $?
509	ip netns exec at_ns0 ping6 $PING_ARG 1::22
510	check_err $?
511	cleanup
512
513	if [ $ret -ne 0 ]; then
514                echo -e ${RED}"FAIL: ip6$TYPE"${NC}
515                return 1
516        fi
517        echo -e ${GREEN}"PASS: ip6$TYPE"${NC}
518}
519
520attach_bpf()
521{
522	DEV=$1
523	SET=$2
524	GET=$3
525	mkdir -p ${BPF_PIN_TUNNEL_DIR}
526	bpftool prog loadall ${BPF_FILE} ${BPF_PIN_TUNNEL_DIR}/
527	tc qdisc add dev $DEV clsact
528	tc filter add dev $DEV egress bpf da object-pinned ${BPF_PIN_TUNNEL_DIR}/$SET
529	tc filter add dev $DEV ingress bpf da object-pinned ${BPF_PIN_TUNNEL_DIR}/$GET
530}
531
532cleanup()
533{
534        rm -rf ${BPF_PIN_TUNNEL_DIR}
535
536	ip netns delete at_ns0 2> /dev/null
537	ip link del veth1 2> /dev/null
538	ip link del ipip11 2> /dev/null
539	ip link del ipip6tnl11 2> /dev/null
540	ip link del ip6ip6tnl11 2> /dev/null
541	ip link del gretap11 2> /dev/null
542	ip link del gre11 2> /dev/null
543	ip link del ip6gre11 2> /dev/null
544	ip link del ip6gretap11 2> /dev/null
545	ip link del geneve11 2> /dev/null
546	ip link del ip6geneve11 2> /dev/null
547	ip link del erspan11 2> /dev/null
548	ip link del ip6erspan11 2> /dev/null
549}
550
551cleanup_exit()
552{
553	echo "CATCH SIGKILL or SIGINT, cleanup and exit"
554	cleanup
555	exit 0
556}
557
558check()
559{
560	ip link help 2>&1 | grep -q "\s$1\s"
561	if [ $? -ne 0 ];then
562		echo "SKIP $1: iproute2 not support"
563	cleanup
564	return 1
565	fi
566}
567
568enable_debug()
569{
570	echo 'file ip_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
571	echo 'file ip6_gre.c +p' > /sys/kernel/debug/dynamic_debug/control
572	echo 'file geneve.c +p' > /sys/kernel/debug/dynamic_debug/control
573	echo 'file ipip.c +p' > /sys/kernel/debug/dynamic_debug/control
574}
575
576check_err()
577{
578	if [ $ret -eq 0 ]; then
579		ret=$1
580	fi
581}
582
583bpf_tunnel_test()
584{
585	local errors=0
586
587	echo "Testing GRE tunnel..."
588	test_gre
589	errors=$(( $errors + $? ))
590
591	echo "Testing GRE tunnel (without tunnel keys)..."
592	test_gre_no_tunnel_key
593	errors=$(( $errors + $? ))
594
595	echo "Testing IP6GRE tunnel..."
596	test_ip6gre
597	errors=$(( $errors + $? ))
598
599	echo "Testing IP6GRETAP tunnel..."
600	test_ip6gretap
601	errors=$(( $errors + $? ))
602
603	echo "Testing ERSPAN tunnel..."
604	test_erspan v2
605	errors=$(( $errors + $? ))
606
607	echo "Testing IP6ERSPAN tunnel..."
608	test_ip6erspan v2
609	errors=$(( $errors + $? ))
610
611	echo "Testing GENEVE tunnel..."
612	test_geneve
613	errors=$(( $errors + $? ))
614
615	echo "Testing IP6GENEVE tunnel..."
616	test_ip6geneve
617	errors=$(( $errors + $? ))
618
619	echo "Testing IPIP tunnel..."
620	test_ipip
621	errors=$(( $errors + $? ))
622
623	echo "Testing IPIP6 tunnel..."
624	test_ipip6
625	errors=$(( $errors + $? ))
626
627	echo "Testing IP6IP6 tunnel..."
628	test_ip6ip6
629	errors=$(( $errors + $? ))
630
631	return $errors
632}
633
634trap cleanup 0 3 6
635trap cleanup_exit 2 9
636
637cleanup
638bpf_tunnel_test
639
640if [ $? -ne 0 ]; then
641	echo -e "$(basename $0): ${RED}FAIL${NC}"
642	exit 1
643fi
644echo -e "$(basename $0): ${GREEN}PASS${NC}"
645exit 0
646