| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| # End-to-end eBPF tunnel test suite |
| # The script tests BPF network tunnel implementation. |
| # |
| # Topology: |
| # --------- |
| # root namespace | at_ns0 namespace |
| # | |
| # ----------- | ----------- |
| # | tnl dev | | | tnl dev | (overlay network) |
| # ----------- | ----------- |
| # metadata-mode | native-mode |
| # with bpf | |
| # | |
| # ---------- | ---------- |
| # | veth1 | --------- | veth0 | (underlay network) |
| # ---------- peer ---------- |
| # |
| # |
| # Device Configuration |
| # -------------------- |
| # Root namespace with metadata-mode tunnel + BPF |
| # Device names and addresses: |
| # veth1 IP: 172.16.1.200, IPv6: 00::22 (underlay) |
| # tunnel dev <type>11, ex: gre11, IPv4: 10.1.1.200, IPv6: 1::22 (overlay) |
| # |
| # Namespace at_ns0 with native tunnel |
| # Device names and addresses: |
| # veth0 IPv4: 172.16.1.100, IPv6: 00::11 (underlay) |
| # tunnel dev <type>00, ex: gre00, IPv4: 10.1.1.100, IPv6: 1::11 (overlay) |
| # |
| # |
| # End-to-end ping packet flow |
| # --------------------------- |
| # Most of the tests start by namespace creation, device configuration, |
| # then ping the underlay and overlay network. When doing 'ping 10.1.1.100' |
| # from root namespace, the following operations happen: |
| # 1) Route lookup shows 10.1.1.100/24 belongs to tnl dev, fwd to tnl dev. |
| # 2) Tnl device's egress BPF program is triggered and set the tunnel metadata, |
| # with remote_ip=172.16.1.100 and others. |
| # 3) Outer tunnel header is prepended and route the packet to veth1's egress |
| # 4) veth0's ingress queue receive the tunneled packet at namespace at_ns0 |
| # 5) Tunnel protocol handler, ex: vxlan_rcv, decap the packet |
| # 6) Forward the packet to the overlay tnl dev |
| |
| BPF_FILE="test_tunnel_kern.bpf.o" |
| BPF_PIN_TUNNEL_DIR="/sys/fs/bpf/tc/tunnel" |
| PING_ARG="-c 3 -w 10 -q" |
| ret=0 |
| GREEN='\033[0;92m' |
| RED='\033[0;31m' |
| NC='\033[0m' # No Color |
| |
| config_device() |
| { |
| ip netns add at_ns0 |
| ip link add veth0 type veth peer name veth1 |
| ip link set veth0 netns at_ns0 |
| ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0 |
| ip netns exec at_ns0 ip link set dev veth0 up |
| ip link set dev veth1 up mtu 1500 |
| ip addr add dev veth1 172.16.1.200/24 |
| } |
| |
| add_gre_tunnel() |
| { |
| tun_key= |
| if [ -n "$1" ]; then |
| tun_key="key $1" |
| fi |
| |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq $tun_key \ |
| local 172.16.1.100 remote 172.16.1.200 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE $tun_key external |
| ip link set dev $DEV up |
| ip addr add dev $DEV 10.1.1.200/24 |
| } |
| |
| add_ip6gretap_tunnel() |
| { |
| |
| # assign ipv6 address |
| ip netns exec at_ns0 ip addr add ::11/96 dev veth0 |
| ip netns exec at_ns0 ip link set dev veth0 up |
| ip addr add dev veth1 ::22/96 |
| ip link set dev veth1 up |
| |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq flowlabel 0xbcdef key 2 \ |
| local ::11 remote ::22 |
| |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| ip netns exec at_ns0 ip addr add dev $DEV_NS fc80::100/96 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip addr add dev $DEV 10.1.1.200/24 |
| ip addr add dev $DEV fc80::200/24 |
| ip link set dev $DEV up |
| } |
| |
| add_erspan_tunnel() |
| { |
| # at_ns0 namespace |
| if [ "$1" == "v1" ]; then |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq key 2 \ |
| local 172.16.1.100 remote 172.16.1.200 \ |
| erspan_ver 1 erspan 123 |
| else |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq key 2 \ |
| local 172.16.1.100 remote 172.16.1.200 \ |
| erspan_ver 2 erspan_dir egress erspan_hwid 3 |
| fi |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip link set dev $DEV up |
| ip addr add dev $DEV 10.1.1.200/24 |
| } |
| |
| add_ip6erspan_tunnel() |
| { |
| |
| # assign ipv6 address |
| ip netns exec at_ns0 ip addr add ::11/96 dev veth0 |
| ip netns exec at_ns0 ip link set dev veth0 up |
| ip addr add dev veth1 ::22/96 |
| ip link set dev veth1 up |
| |
| # at_ns0 namespace |
| if [ "$1" == "v1" ]; then |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq key 2 \ |
| local ::11 remote ::22 \ |
| erspan_ver 1 erspan 123 |
| else |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE seq key 2 \ |
| local ::11 remote ::22 \ |
| erspan_ver 2 erspan_dir egress erspan_hwid 7 |
| fi |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip addr add dev $DEV 10.1.1.200/24 |
| ip link set dev $DEV up |
| } |
| |
| add_geneve_tunnel() |
| { |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE \ |
| id 2 dstport 6081 remote 172.16.1.200 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE dstport 6081 external |
| ip link set dev $DEV up |
| ip addr add dev $DEV 10.1.1.200/24 |
| } |
| |
| add_ip6geneve_tunnel() |
| { |
| ip netns exec at_ns0 ip addr add ::11/96 dev veth0 |
| ip netns exec at_ns0 ip link set dev veth0 up |
| ip addr add dev veth1 ::22/96 |
| ip link set dev veth1 up |
| |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE id 22 \ |
| remote ::22 # geneve has no local option |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip addr add dev $DEV 10.1.1.200/24 |
| ip link set dev $DEV up |
| } |
| |
| add_ipip_tunnel() |
| { |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE \ |
| local 172.16.1.100 remote 172.16.1.200 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip link set dev $DEV up |
| ip addr add dev $DEV 10.1.1.200/24 |
| } |
| |
| add_ip6tnl_tunnel() |
| { |
| ip netns exec at_ns0 ip addr add ::11/96 dev veth0 |
| ip netns exec at_ns0 ip link set dev veth0 up |
| ip addr add dev veth1 ::22/96 |
| ip link set dev veth1 up |
| |
| # at_ns0 namespace |
| ip netns exec at_ns0 \ |
| ip link add dev $DEV_NS type $TYPE \ |
| local ::11 remote ::22 |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 10.1.1.100/24 |
| ip netns exec at_ns0 ip addr add dev $DEV_NS 1::11/96 |
| ip netns exec at_ns0 ip link set dev $DEV_NS up |
| |
| # root namespace |
| ip link add dev $DEV type $TYPE external |
| ip addr add dev $DEV 10.1.1.200/24 |
| ip addr add dev $DEV 1::22/96 |
| ip link set dev $DEV up |
| } |
| |
| test_gre() |
| { |
| TYPE=gretap |
| DEV_NS=gretap00 |
| DEV=gretap11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_gre_tunnel 2 |
| attach_bpf $DEV gre_set_tunnel gre_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_gre_no_tunnel_key() |
| { |
| TYPE=gre |
| DEV_NS=gre00 |
| DEV=gre11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_gre_tunnel |
| attach_bpf $DEV gre_set_tunnel_no_key gre_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ip6gre() |
| { |
| TYPE=ip6gre |
| DEV_NS=ip6gre00 |
| DEV=ip6gre11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| # reuse the ip6gretap function |
| add_ip6gretap_tunnel |
| attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel |
| # underlay |
| ping6 $PING_ARG ::11 |
| # overlay: ipv4 over ipv6 |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| # overlay: ipv6 over ipv6 |
| ip netns exec at_ns0 ping6 $PING_ARG fc80::200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ip6gretap() |
| { |
| TYPE=ip6gretap |
| DEV_NS=ip6gretap00 |
| DEV=ip6gretap11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ip6gretap_tunnel |
| attach_bpf $DEV ip6gretap_set_tunnel ip6gretap_get_tunnel |
| # underlay |
| ping6 $PING_ARG ::11 |
| # overlay: ipv4 over ipv6 |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| # overlay: ipv6 over ipv6 |
| ip netns exec at_ns0 ping6 $PING_ARG fc80::200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_erspan() |
| { |
| TYPE=erspan |
| DEV_NS=erspan00 |
| DEV=erspan11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_erspan_tunnel $1 |
| attach_bpf $DEV erspan_set_tunnel erspan_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ip6erspan() |
| { |
| TYPE=ip6erspan |
| DEV_NS=ip6erspan00 |
| DEV=ip6erspan11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ip6erspan_tunnel $1 |
| attach_bpf $DEV ip4ip6erspan_set_tunnel ip4ip6erspan_get_tunnel |
| ping6 $PING_ARG ::11 |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_geneve() |
| { |
| TYPE=geneve |
| DEV_NS=geneve00 |
| DEV=geneve11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_geneve_tunnel |
| attach_bpf $DEV geneve_set_tunnel geneve_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ip6geneve() |
| { |
| TYPE=geneve |
| DEV_NS=ip6geneve00 |
| DEV=ip6geneve11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ip6geneve_tunnel |
| attach_bpf $DEV ip6geneve_set_tunnel ip6geneve_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: ip6$TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: ip6$TYPE"${NC} |
| } |
| |
| test_ipip() |
| { |
| TYPE=ipip |
| DEV_NS=ipip00 |
| DEV=ipip11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ipip_tunnel |
| ip link set dev veth1 mtu 1500 |
| attach_bpf $DEV ipip_set_tunnel ipip_get_tunnel |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ipip6() |
| { |
| TYPE=ip6tnl |
| DEV_NS=ipip6tnl00 |
| DEV=ipip6tnl11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ip6tnl_tunnel |
| ip link set dev veth1 mtu 1500 |
| attach_bpf $DEV ipip6_set_tunnel ipip6_get_tunnel |
| # underlay |
| ping6 $PING_ARG ::11 |
| # ip4 over ip6 |
| ping $PING_ARG 10.1.1.100 |
| check_err $? |
| ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: $TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: $TYPE"${NC} |
| } |
| |
| test_ip6ip6() |
| { |
| TYPE=ip6tnl |
| DEV_NS=ip6ip6tnl00 |
| DEV=ip6ip6tnl11 |
| ret=0 |
| |
| check $TYPE |
| config_device |
| add_ip6tnl_tunnel |
| ip link set dev veth1 mtu 1500 |
| attach_bpf $DEV ip6ip6_set_tunnel ip6ip6_get_tunnel |
| # underlay |
| ping6 $PING_ARG ::11 |
| # ip6 over ip6 |
| ping6 $PING_ARG 1::11 |
| check_err $? |
| ip netns exec at_ns0 ping6 $PING_ARG 1::22 |
| check_err $? |
| cleanup |
| |
| if [ $ret -ne 0 ]; then |
| echo -e ${RED}"FAIL: ip6$TYPE"${NC} |
| return 1 |
| fi |
| echo -e ${GREEN}"PASS: ip6$TYPE"${NC} |
| } |
| |
| attach_bpf() |
| { |
| DEV=$1 |
| SET=$2 |
| GET=$3 |
| mkdir -p ${BPF_PIN_TUNNEL_DIR} |
| bpftool prog loadall ${BPF_FILE} ${BPF_PIN_TUNNEL_DIR}/ |
| tc qdisc add dev $DEV clsact |
| tc filter add dev $DEV egress bpf da object-pinned ${BPF_PIN_TUNNEL_DIR}/$SET |
| tc filter add dev $DEV ingress bpf da object-pinned ${BPF_PIN_TUNNEL_DIR}/$GET |
| } |
| |
| cleanup() |
| { |
| rm -rf ${BPF_PIN_TUNNEL_DIR} |
| |
| ip netns delete at_ns0 2> /dev/null |
| ip link del veth1 2> /dev/null |
| ip link del ipip11 2> /dev/null |
| ip link del ipip6tnl11 2> /dev/null |
| ip link del ip6ip6tnl11 2> /dev/null |
| ip link del gretap11 2> /dev/null |
| ip link del gre11 2> /dev/null |
| ip link del ip6gre11 2> /dev/null |
| ip link del ip6gretap11 2> /dev/null |
| ip link del geneve11 2> /dev/null |
| ip link del ip6geneve11 2> /dev/null |
| ip link del erspan11 2> /dev/null |
| ip link del ip6erspan11 2> /dev/null |
| } |
| |
| cleanup_exit() |
| { |
| echo "CATCH SIGKILL or SIGINT, cleanup and exit" |
| cleanup |
| exit 0 |
| } |
| |
| check() |
| { |
| ip link help 2>&1 | grep -q "\s$1\s" |
| if [ $? -ne 0 ];then |
| echo "SKIP $1: iproute2 not support" |
| cleanup |
| return 1 |
| fi |
| } |
| |
| enable_debug() |
| { |
| echo 'file ip_gre.c +p' > /sys/kernel/debug/dynamic_debug/control |
| echo 'file ip6_gre.c +p' > /sys/kernel/debug/dynamic_debug/control |
| echo 'file geneve.c +p' > /sys/kernel/debug/dynamic_debug/control |
| echo 'file ipip.c +p' > /sys/kernel/debug/dynamic_debug/control |
| } |
| |
| check_err() |
| { |
| if [ $ret -eq 0 ]; then |
| ret=$1 |
| fi |
| } |
| |
| bpf_tunnel_test() |
| { |
| local errors=0 |
| |
| echo "Testing GRE tunnel..." |
| test_gre |
| errors=$(( $errors + $? )) |
| |
| echo "Testing GRE tunnel (without tunnel keys)..." |
| test_gre_no_tunnel_key |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IP6GRE tunnel..." |
| test_ip6gre |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IP6GRETAP tunnel..." |
| test_ip6gretap |
| errors=$(( $errors + $? )) |
| |
| echo "Testing ERSPAN tunnel..." |
| test_erspan v2 |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IP6ERSPAN tunnel..." |
| test_ip6erspan v2 |
| errors=$(( $errors + $? )) |
| |
| echo "Testing GENEVE tunnel..." |
| test_geneve |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IP6GENEVE tunnel..." |
| test_ip6geneve |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IPIP tunnel..." |
| test_ipip |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IPIP6 tunnel..." |
| test_ipip6 |
| errors=$(( $errors + $? )) |
| |
| echo "Testing IP6IP6 tunnel..." |
| test_ip6ip6 |
| errors=$(( $errors + $? )) |
| |
| return $errors |
| } |
| |
| trap cleanup 0 3 6 |
| trap cleanup_exit 2 9 |
| |
| cleanup |
| bpf_tunnel_test |
| |
| if [ $? -ne 0 ]; then |
| echo -e "$(basename $0): ${RED}FAIL${NC}" |
| exit 1 |
| fi |
| echo -e "$(basename $0): ${GREEN}PASS${NC}" |
| exit 0 |