1*4882a593Smuzhiyun#!/bin/bash 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# In-place tunneling 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun# must match the port that the bpf program filters on 7*4882a593Smuzhiyunreadonly port=8000 8*4882a593Smuzhiyun 9*4882a593Smuzhiyunreadonly ns_prefix="ns-$$-" 10*4882a593Smuzhiyunreadonly ns1="${ns_prefix}1" 11*4882a593Smuzhiyunreadonly ns2="${ns_prefix}2" 12*4882a593Smuzhiyun 13*4882a593Smuzhiyunreadonly ns1_v4=192.168.1.1 14*4882a593Smuzhiyunreadonly ns2_v4=192.168.1.2 15*4882a593Smuzhiyunreadonly ns1_v6=fd::1 16*4882a593Smuzhiyunreadonly ns2_v6=fd::2 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun# Must match port used by bpf program 19*4882a593Smuzhiyunreadonly udpport=5555 20*4882a593Smuzhiyun# MPLSoverUDP 21*4882a593Smuzhiyunreadonly mplsudpport=6635 22*4882a593Smuzhiyunreadonly mplsproto=137 23*4882a593Smuzhiyun 24*4882a593Smuzhiyunreadonly infile="$(mktemp)" 25*4882a593Smuzhiyunreadonly outfile="$(mktemp)" 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunsetup() { 28*4882a593Smuzhiyun ip netns add "${ns1}" 29*4882a593Smuzhiyun ip netns add "${ns2}" 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \ 32*4882a593Smuzhiyun peer name veth2 mtu 1500 netns "${ns2}" 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun ip netns exec "${ns1}" ethtool -K veth1 tso off 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun ip -netns "${ns1}" link set veth1 up 37*4882a593Smuzhiyun ip -netns "${ns2}" link set veth2 up 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1 40*4882a593Smuzhiyun ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2 41*4882a593Smuzhiyun ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad 42*4882a593Smuzhiyun ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad 43*4882a593Smuzhiyun 44*4882a593Smuzhiyun # clamp route to reserve room for tunnel headers 45*4882a593Smuzhiyun ip -netns "${ns1}" -4 route flush table main 46*4882a593Smuzhiyun ip -netns "${ns1}" -6 route flush table main 47*4882a593Smuzhiyun ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1458 dev veth1 48*4882a593Smuzhiyun ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1438 dev veth1 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun sleep 1 51*4882a593Smuzhiyun 52*4882a593Smuzhiyun dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none 53*4882a593Smuzhiyun} 54*4882a593Smuzhiyun 55*4882a593Smuzhiyuncleanup() { 56*4882a593Smuzhiyun ip netns del "${ns2}" 57*4882a593Smuzhiyun ip netns del "${ns1}" 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun if [[ -f "${outfile}" ]]; then 60*4882a593Smuzhiyun rm "${outfile}" 61*4882a593Smuzhiyun fi 62*4882a593Smuzhiyun if [[ -f "${infile}" ]]; then 63*4882a593Smuzhiyun rm "${infile}" 64*4882a593Smuzhiyun fi 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun if [[ -n $server_pid ]]; then 67*4882a593Smuzhiyun kill $server_pid 2> /dev/null 68*4882a593Smuzhiyun fi 69*4882a593Smuzhiyun} 70*4882a593Smuzhiyun 71*4882a593Smuzhiyunserver_listen() { 72*4882a593Smuzhiyun ip netns exec "${ns2}" nc "${netcat_opt}" -l -p "${port}" > "${outfile}" & 73*4882a593Smuzhiyun server_pid=$! 74*4882a593Smuzhiyun sleep 0.2 75*4882a593Smuzhiyun} 76*4882a593Smuzhiyun 77*4882a593Smuzhiyunclient_connect() { 78*4882a593Smuzhiyun ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}" 79*4882a593Smuzhiyun echo $? 80*4882a593Smuzhiyun} 81*4882a593Smuzhiyun 82*4882a593Smuzhiyunverify_data() { 83*4882a593Smuzhiyun wait "${server_pid}" 84*4882a593Smuzhiyun server_pid= 85*4882a593Smuzhiyun # sha1sum returns two fields [sha1] [filepath] 86*4882a593Smuzhiyun # convert to bash array and access first elem 87*4882a593Smuzhiyun insum=($(sha1sum ${infile})) 88*4882a593Smuzhiyun outsum=($(sha1sum ${outfile})) 89*4882a593Smuzhiyun if [[ "${insum[0]}" != "${outsum[0]}" ]]; then 90*4882a593Smuzhiyun echo "data mismatch" 91*4882a593Smuzhiyun exit 1 92*4882a593Smuzhiyun fi 93*4882a593Smuzhiyun} 94*4882a593Smuzhiyun 95*4882a593Smuzhiyunset -e 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun# no arguments: automated test, run all 98*4882a593Smuzhiyunif [[ "$#" -eq "0" ]]; then 99*4882a593Smuzhiyun echo "ipip" 100*4882a593Smuzhiyun $0 ipv4 ipip none 100 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun echo "ip6ip6" 103*4882a593Smuzhiyun $0 ipv6 ip6tnl none 100 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun echo "sit" 106*4882a593Smuzhiyun $0 ipv6 sit none 100 107*4882a593Smuzhiyun 108*4882a593Smuzhiyun for mac in none mpls eth ; do 109*4882a593Smuzhiyun echo "ip gre $mac" 110*4882a593Smuzhiyun $0 ipv4 gre $mac 100 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun echo "ip6 gre $mac" 113*4882a593Smuzhiyun $0 ipv6 ip6gre $mac 100 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun echo "ip gre $mac gso" 116*4882a593Smuzhiyun $0 ipv4 gre $mac 2000 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun echo "ip6 gre $mac gso" 119*4882a593Smuzhiyun $0 ipv6 ip6gre $mac 2000 120*4882a593Smuzhiyun 121*4882a593Smuzhiyun echo "ip udp $mac" 122*4882a593Smuzhiyun $0 ipv4 udp $mac 100 123*4882a593Smuzhiyun 124*4882a593Smuzhiyun echo "ip6 udp $mac" 125*4882a593Smuzhiyun $0 ipv6 ip6udp $mac 100 126*4882a593Smuzhiyun 127*4882a593Smuzhiyun echo "ip udp $mac gso" 128*4882a593Smuzhiyun $0 ipv4 udp $mac 2000 129*4882a593Smuzhiyun 130*4882a593Smuzhiyun echo "ip6 udp $mac gso" 131*4882a593Smuzhiyun $0 ipv6 ip6udp $mac 2000 132*4882a593Smuzhiyun done 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun echo "OK. All tests passed" 135*4882a593Smuzhiyun exit 0 136*4882a593Smuzhiyunfi 137*4882a593Smuzhiyun 138*4882a593Smuzhiyunif [[ "$#" -ne "4" ]]; then 139*4882a593Smuzhiyun echo "Usage: $0" 140*4882a593Smuzhiyun echo " or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>" 141*4882a593Smuzhiyun exit 1 142*4882a593Smuzhiyunfi 143*4882a593Smuzhiyun 144*4882a593Smuzhiyuncase "$1" in 145*4882a593Smuzhiyun"ipv4") 146*4882a593Smuzhiyun readonly addr1="${ns1_v4}" 147*4882a593Smuzhiyun readonly addr2="${ns2_v4}" 148*4882a593Smuzhiyun readonly ipproto=4 149*4882a593Smuzhiyun readonly netcat_opt=-${ipproto} 150*4882a593Smuzhiyun readonly foumod=fou 151*4882a593Smuzhiyun readonly foutype=ipip 152*4882a593Smuzhiyun readonly fouproto=4 153*4882a593Smuzhiyun readonly fouproto_mpls=${mplsproto} 154*4882a593Smuzhiyun readonly gretaptype=gretap 155*4882a593Smuzhiyun ;; 156*4882a593Smuzhiyun"ipv6") 157*4882a593Smuzhiyun readonly addr1="${ns1_v6}" 158*4882a593Smuzhiyun readonly addr2="${ns2_v6}" 159*4882a593Smuzhiyun readonly ipproto=6 160*4882a593Smuzhiyun readonly netcat_opt=-${ipproto} 161*4882a593Smuzhiyun readonly foumod=fou6 162*4882a593Smuzhiyun readonly foutype=ip6tnl 163*4882a593Smuzhiyun readonly fouproto="41 -6" 164*4882a593Smuzhiyun readonly fouproto_mpls="${mplsproto} -6" 165*4882a593Smuzhiyun readonly gretaptype=ip6gretap 166*4882a593Smuzhiyun ;; 167*4882a593Smuzhiyun*) 168*4882a593Smuzhiyun echo "unknown arg: $1" 169*4882a593Smuzhiyun exit 1 170*4882a593Smuzhiyun ;; 171*4882a593Smuzhiyunesac 172*4882a593Smuzhiyun 173*4882a593Smuzhiyunreadonly tuntype=$2 174*4882a593Smuzhiyunreadonly mac=$3 175*4882a593Smuzhiyunreadonly datalen=$4 176*4882a593Smuzhiyun 177*4882a593Smuzhiyunecho "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}" 178*4882a593Smuzhiyun 179*4882a593Smuzhiyuntrap cleanup EXIT 180*4882a593Smuzhiyun 181*4882a593Smuzhiyunsetup 182*4882a593Smuzhiyun 183*4882a593Smuzhiyun# basic communication works 184*4882a593Smuzhiyunecho "test basic connectivity" 185*4882a593Smuzhiyunserver_listen 186*4882a593Smuzhiyunclient_connect 187*4882a593Smuzhiyunverify_data 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun# clientside, insert bpf program to encap all TCP to port ${port} 190*4882a593Smuzhiyun# client can no longer connect 191*4882a593Smuzhiyunip netns exec "${ns1}" tc qdisc add dev veth1 clsact 192*4882a593Smuzhiyunip netns exec "${ns1}" tc filter add dev veth1 egress \ 193*4882a593Smuzhiyun bpf direct-action object-file ./test_tc_tunnel.o \ 194*4882a593Smuzhiyun section "encap_${tuntype}_${mac}" 195*4882a593Smuzhiyunecho "test bpf encap without decap (expect failure)" 196*4882a593Smuzhiyunserver_listen 197*4882a593Smuzhiyun! client_connect 198*4882a593Smuzhiyun 199*4882a593Smuzhiyunif [[ "$tuntype" =~ "udp" ]]; then 200*4882a593Smuzhiyun # Set up fou tunnel. 201*4882a593Smuzhiyun ttype="${foutype}" 202*4882a593Smuzhiyun targs="encap fou encap-sport auto encap-dport $udpport" 203*4882a593Smuzhiyun # fou may be a module; allow this to fail. 204*4882a593Smuzhiyun modprobe "${foumod}" ||true 205*4882a593Smuzhiyun if [[ "$mac" == "mpls" ]]; then 206*4882a593Smuzhiyun dport=${mplsudpport} 207*4882a593Smuzhiyun dproto=${fouproto_mpls} 208*4882a593Smuzhiyun tmode="mode any ttl 255" 209*4882a593Smuzhiyun else 210*4882a593Smuzhiyun dport=${udpport} 211*4882a593Smuzhiyun dproto=${fouproto} 212*4882a593Smuzhiyun fi 213*4882a593Smuzhiyun ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto} 214*4882a593Smuzhiyun targs="encap fou encap-sport auto encap-dport $dport" 215*4882a593Smuzhiyunelif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then 216*4882a593Smuzhiyun ttype=$gretaptype 217*4882a593Smuzhiyunelse 218*4882a593Smuzhiyun ttype=$tuntype 219*4882a593Smuzhiyun targs="" 220*4882a593Smuzhiyunfi 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun# tunnel address family differs from inner for SIT 223*4882a593Smuzhiyunif [[ "${tuntype}" == "sit" ]]; then 224*4882a593Smuzhiyun link_addr1="${ns1_v4}" 225*4882a593Smuzhiyun link_addr2="${ns2_v4}" 226*4882a593Smuzhiyunelse 227*4882a593Smuzhiyun link_addr1="${addr1}" 228*4882a593Smuzhiyun link_addr2="${addr2}" 229*4882a593Smuzhiyunfi 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun# serverside, insert decap module 232*4882a593Smuzhiyun# server is still running 233*4882a593Smuzhiyun# client can connect again 234*4882a593Smuzhiyunip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \ 235*4882a593Smuzhiyun ${tmode} remote "${link_addr1}" local "${link_addr2}" $targs 236*4882a593Smuzhiyun 237*4882a593Smuzhiyunexpect_tun_fail=0 238*4882a593Smuzhiyun 239*4882a593Smuzhiyunif [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then 240*4882a593Smuzhiyun # No support for MPLS IPv6 fou tunnel; expect failure. 241*4882a593Smuzhiyun expect_tun_fail=1 242*4882a593Smuzhiyunelif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then 243*4882a593Smuzhiyun # No support for TEB fou tunnel; expect failure. 244*4882a593Smuzhiyun expect_tun_fail=1 245*4882a593Smuzhiyunelif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then 246*4882a593Smuzhiyun # Share ethernet address between tunnel/veth2 so L2 decap works. 247*4882a593Smuzhiyun ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \ 248*4882a593Smuzhiyun awk '/ether/ { print $2 }') 249*4882a593Smuzhiyun ip netns exec "${ns2}" ip link set testtun0 address $ethaddr 250*4882a593Smuzhiyunelif [[ "$mac" == "mpls" ]]; then 251*4882a593Smuzhiyun modprobe mpls_iptunnel ||true 252*4882a593Smuzhiyun modprobe mpls_gso ||true 253*4882a593Smuzhiyun ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536 254*4882a593Smuzhiyun ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo 255*4882a593Smuzhiyun ip netns exec "${ns2}" ip link set lo up 256*4882a593Smuzhiyun ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1 257*4882a593Smuzhiyun ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0 258*4882a593Smuzhiyunfi 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun# Because packets are decapped by the tunnel they arrive on testtun0 from 261*4882a593Smuzhiyun# the IP stack perspective. Ensure reverse path filtering is disabled 262*4882a593Smuzhiyun# otherwise we drop the TCP SYN as arriving on testtun0 instead of the 263*4882a593Smuzhiyun# expected veth2 (veth2 is where 192.168.1.2 is configured). 264*4882a593Smuzhiyunip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0 265*4882a593Smuzhiyun# rp needs to be disabled for both all and testtun0 as the rp value is 266*4882a593Smuzhiyun# selected as the max of the "all" and device-specific values. 267*4882a593Smuzhiyunip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0 268*4882a593Smuzhiyunip netns exec "${ns2}" ip link set dev testtun0 up 269*4882a593Smuzhiyunif [[ "$expect_tun_fail" == 1 ]]; then 270*4882a593Smuzhiyun # This tunnel mode is not supported, so we expect failure. 271*4882a593Smuzhiyun echo "test bpf encap with tunnel device decap (expect failure)" 272*4882a593Smuzhiyun ! client_connect 273*4882a593Smuzhiyunelse 274*4882a593Smuzhiyun echo "test bpf encap with tunnel device decap" 275*4882a593Smuzhiyun client_connect 276*4882a593Smuzhiyun verify_data 277*4882a593Smuzhiyun server_listen 278*4882a593Smuzhiyunfi 279*4882a593Smuzhiyun 280*4882a593Smuzhiyun# bpf_skb_net_shrink does not take tunnel flags yet, cannot update L3. 281*4882a593Smuzhiyunif [[ "${tuntype}" == "sit" ]]; then 282*4882a593Smuzhiyun echo OK 283*4882a593Smuzhiyun exit 0 284*4882a593Smuzhiyunfi 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun# serverside, use BPF for decap 287*4882a593Smuzhiyunip netns exec "${ns2}" ip link del dev testtun0 288*4882a593Smuzhiyunip netns exec "${ns2}" tc qdisc add dev veth2 clsact 289*4882a593Smuzhiyunip netns exec "${ns2}" tc filter add dev veth2 ingress \ 290*4882a593Smuzhiyun bpf direct-action object-file ./test_tc_tunnel.o section decap 291*4882a593Smuzhiyunecho "test bpf encap with bpf decap" 292*4882a593Smuzhiyunclient_connect 293*4882a593Smuzhiyunverify_data 294*4882a593Smuzhiyun 295*4882a593Smuzhiyunecho OK 296