f803bcf920
In some systems, the netcat server can incur in delay to start listening. When this happens, the test can randomly fail in various points. This is an example error message: # ip gre none gso # encap 192.168.1.1 to 192.168.1.2, type gre, mac none len 2000 # test basic connectivity # Ncat: Connection refused. The issue stems from a race condition between the netcat client and server. The test author had addressed this problem by implementing a sleep, which I have removed in this patch. This patch introduces a function capable of sleeping for up to two seconds. However, it can terminate the waiting period early if the port is reported to be listening. Signed-off-by: Alessandro Carminati (Red Hat) <alessandro.carminati@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20240314105911.213411-1-alessandro.carminati@gmail.com
320 lines
7.8 KiB
Bash
Executable File
320 lines
7.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# SPDX-License-Identifier: GPL-2.0
|
|
#
|
|
# In-place tunneling
|
|
|
|
BPF_FILE="test_tc_tunnel.bpf.o"
|
|
# must match the port that the bpf program filters on
|
|
readonly port=8000
|
|
|
|
readonly ns_prefix="ns-$$-"
|
|
readonly ns1="${ns_prefix}1"
|
|
readonly ns2="${ns_prefix}2"
|
|
|
|
readonly ns1_v4=192.168.1.1
|
|
readonly ns2_v4=192.168.1.2
|
|
readonly ns1_v6=fd::1
|
|
readonly ns2_v6=fd::2
|
|
|
|
# Must match port used by bpf program
|
|
readonly udpport=5555
|
|
# MPLSoverUDP
|
|
readonly mplsudpport=6635
|
|
readonly mplsproto=137
|
|
|
|
readonly infile="$(mktemp)"
|
|
readonly outfile="$(mktemp)"
|
|
|
|
setup() {
|
|
ip netns add "${ns1}"
|
|
ip netns add "${ns2}"
|
|
|
|
ip link add dev veth1 mtu 1500 netns "${ns1}" type veth \
|
|
peer name veth2 mtu 1500 netns "${ns2}"
|
|
|
|
ip netns exec "${ns1}" ethtool -K veth1 tso off
|
|
|
|
ip -netns "${ns1}" link set veth1 up
|
|
ip -netns "${ns2}" link set veth2 up
|
|
|
|
ip -netns "${ns1}" -4 addr add "${ns1_v4}/24" dev veth1
|
|
ip -netns "${ns2}" -4 addr add "${ns2_v4}/24" dev veth2
|
|
ip -netns "${ns1}" -6 addr add "${ns1_v6}/64" dev veth1 nodad
|
|
ip -netns "${ns2}" -6 addr add "${ns2_v6}/64" dev veth2 nodad
|
|
|
|
# clamp route to reserve room for tunnel headers
|
|
ip -netns "${ns1}" -4 route flush table main
|
|
ip -netns "${ns1}" -6 route flush table main
|
|
ip -netns "${ns1}" -4 route add "${ns2_v4}" mtu 1450 dev veth1
|
|
ip -netns "${ns1}" -6 route add "${ns2_v6}" mtu 1430 dev veth1
|
|
|
|
sleep 1
|
|
|
|
dd if=/dev/urandom of="${infile}" bs="${datalen}" count=1 status=none
|
|
}
|
|
|
|
cleanup() {
|
|
ip netns del "${ns2}"
|
|
ip netns del "${ns1}"
|
|
|
|
if [[ -f "${outfile}" ]]; then
|
|
rm "${outfile}"
|
|
fi
|
|
if [[ -f "${infile}" ]]; then
|
|
rm "${infile}"
|
|
fi
|
|
|
|
if [[ -n $server_pid ]]; then
|
|
kill $server_pid 2> /dev/null
|
|
fi
|
|
}
|
|
|
|
server_listen() {
|
|
ip netns exec "${ns2}" nc "${netcat_opt}" -l "${port}" > "${outfile}" &
|
|
server_pid=$!
|
|
}
|
|
|
|
client_connect() {
|
|
ip netns exec "${ns1}" timeout 2 nc "${netcat_opt}" -w 1 "${addr2}" "${port}" < "${infile}"
|
|
echo $?
|
|
}
|
|
|
|
verify_data() {
|
|
wait "${server_pid}"
|
|
server_pid=
|
|
# sha1sum returns two fields [sha1] [filepath]
|
|
# convert to bash array and access first elem
|
|
insum=($(sha1sum ${infile}))
|
|
outsum=($(sha1sum ${outfile}))
|
|
if [[ "${insum[0]}" != "${outsum[0]}" ]]; then
|
|
echo "data mismatch"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
wait_for_port() {
|
|
for i in $(seq 20); do
|
|
if ip netns exec "${ns2}" ss ${2:--4}OHntl | grep -q "$1"; then
|
|
return 0
|
|
fi
|
|
sleep 0.1
|
|
done
|
|
return 1
|
|
}
|
|
|
|
set -e
|
|
|
|
# no arguments: automated test, run all
|
|
if [[ "$#" -eq "0" ]]; then
|
|
echo "ipip"
|
|
$0 ipv4 ipip none 100
|
|
|
|
echo "ipip6"
|
|
$0 ipv4 ipip6 none 100
|
|
|
|
echo "ip6ip6"
|
|
$0 ipv6 ip6tnl none 100
|
|
|
|
echo "sit"
|
|
$0 ipv6 sit none 100
|
|
|
|
echo "ip4 vxlan"
|
|
$0 ipv4 vxlan eth 2000
|
|
|
|
echo "ip6 vxlan"
|
|
$0 ipv6 ip6vxlan eth 2000
|
|
|
|
for mac in none mpls eth ; do
|
|
echo "ip gre $mac"
|
|
$0 ipv4 gre $mac 100
|
|
|
|
echo "ip6 gre $mac"
|
|
$0 ipv6 ip6gre $mac 100
|
|
|
|
echo "ip gre $mac gso"
|
|
$0 ipv4 gre $mac 2000
|
|
|
|
echo "ip6 gre $mac gso"
|
|
$0 ipv6 ip6gre $mac 2000
|
|
|
|
echo "ip udp $mac"
|
|
$0 ipv4 udp $mac 100
|
|
|
|
echo "ip6 udp $mac"
|
|
$0 ipv6 ip6udp $mac 100
|
|
|
|
echo "ip udp $mac gso"
|
|
$0 ipv4 udp $mac 2000
|
|
|
|
echo "ip6 udp $mac gso"
|
|
$0 ipv6 ip6udp $mac 2000
|
|
done
|
|
|
|
echo "OK. All tests passed"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ "$#" -ne "4" ]]; then
|
|
echo "Usage: $0"
|
|
echo " or: $0 <ipv4|ipv6> <tuntype> <none|mpls|eth> <data_len>"
|
|
exit 1
|
|
fi
|
|
|
|
case "$1" in
|
|
"ipv4")
|
|
readonly addr1="${ns1_v4}"
|
|
readonly addr2="${ns2_v4}"
|
|
readonly ipproto=4
|
|
readonly netcat_opt=-${ipproto}
|
|
readonly foumod=fou
|
|
readonly foutype=ipip
|
|
readonly fouproto=4
|
|
readonly fouproto_mpls=${mplsproto}
|
|
readonly gretaptype=gretap
|
|
;;
|
|
"ipv6")
|
|
readonly addr1="${ns1_v6}"
|
|
readonly addr2="${ns2_v6}"
|
|
readonly ipproto=6
|
|
readonly netcat_opt=-${ipproto}
|
|
readonly foumod=fou6
|
|
readonly foutype=ip6tnl
|
|
readonly fouproto="41 -6"
|
|
readonly fouproto_mpls="${mplsproto} -6"
|
|
readonly gretaptype=ip6gretap
|
|
;;
|
|
*)
|
|
echo "unknown arg: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
readonly tuntype=$2
|
|
readonly mac=$3
|
|
readonly datalen=$4
|
|
|
|
echo "encap ${addr1} to ${addr2}, type ${tuntype}, mac ${mac} len ${datalen}"
|
|
|
|
trap cleanup EXIT
|
|
|
|
setup
|
|
|
|
# basic communication works
|
|
echo "test basic connectivity"
|
|
server_listen
|
|
wait_for_port ${port} ${netcat_opt}
|
|
client_connect
|
|
verify_data
|
|
|
|
# clientside, insert bpf program to encap all TCP to port ${port}
|
|
# client can no longer connect
|
|
ip netns exec "${ns1}" tc qdisc add dev veth1 clsact
|
|
ip netns exec "${ns1}" tc filter add dev veth1 egress \
|
|
bpf direct-action object-file ${BPF_FILE} \
|
|
section "encap_${tuntype}_${mac}"
|
|
echo "test bpf encap without decap (expect failure)"
|
|
server_listen
|
|
wait_for_port ${port} ${netcat_opt}
|
|
! client_connect
|
|
|
|
if [[ "$tuntype" =~ "udp" ]]; then
|
|
# Set up fou tunnel.
|
|
ttype="${foutype}"
|
|
targs="encap fou encap-sport auto encap-dport $udpport"
|
|
# fou may be a module; allow this to fail.
|
|
modprobe "${foumod}" ||true
|
|
if [[ "$mac" == "mpls" ]]; then
|
|
dport=${mplsudpport}
|
|
dproto=${fouproto_mpls}
|
|
tmode="mode any ttl 255"
|
|
else
|
|
dport=${udpport}
|
|
dproto=${fouproto}
|
|
fi
|
|
ip netns exec "${ns2}" ip fou add port $dport ipproto ${dproto}
|
|
targs="encap fou encap-sport auto encap-dport $dport"
|
|
elif [[ "$tuntype" =~ "gre" && "$mac" == "eth" ]]; then
|
|
ttype=$gretaptype
|
|
elif [[ "$tuntype" =~ "vxlan" && "$mac" == "eth" ]]; then
|
|
ttype="vxlan"
|
|
targs="id 1 dstport 8472 udp6zerocsumrx"
|
|
elif [[ "$tuntype" == "ipip6" ]]; then
|
|
ttype="ip6tnl"
|
|
targs=""
|
|
else
|
|
ttype=$tuntype
|
|
targs=""
|
|
fi
|
|
|
|
# tunnel address family differs from inner for SIT
|
|
if [[ "${tuntype}" == "sit" ]]; then
|
|
link_addr1="${ns1_v4}"
|
|
link_addr2="${ns2_v4}"
|
|
elif [[ "${tuntype}" == "ipip6" ]]; then
|
|
link_addr1="${ns1_v6}"
|
|
link_addr2="${ns2_v6}"
|
|
else
|
|
link_addr1="${addr1}"
|
|
link_addr2="${addr2}"
|
|
fi
|
|
|
|
# serverside, insert decap module
|
|
# server is still running
|
|
# client can connect again
|
|
ip netns exec "${ns2}" ip link add name testtun0 type "${ttype}" \
|
|
${tmode} remote "${link_addr1}" local "${link_addr2}" $targs
|
|
|
|
expect_tun_fail=0
|
|
|
|
if [[ "$tuntype" == "ip6udp" && "$mac" == "mpls" ]]; then
|
|
# No support for MPLS IPv6 fou tunnel; expect failure.
|
|
expect_tun_fail=1
|
|
elif [[ "$tuntype" =~ "udp" && "$mac" == "eth" ]]; then
|
|
# No support for TEB fou tunnel; expect failure.
|
|
expect_tun_fail=1
|
|
elif [[ "$tuntype" =~ (gre|vxlan) && "$mac" == "eth" ]]; then
|
|
# Share ethernet address between tunnel/veth2 so L2 decap works.
|
|
ethaddr=$(ip netns exec "${ns2}" ip link show veth2 | \
|
|
awk '/ether/ { print $2 }')
|
|
ip netns exec "${ns2}" ip link set testtun0 address $ethaddr
|
|
elif [[ "$mac" == "mpls" ]]; then
|
|
modprobe mpls_iptunnel ||true
|
|
modprobe mpls_gso ||true
|
|
ip netns exec "${ns2}" sysctl -qw net.mpls.platform_labels=65536
|
|
ip netns exec "${ns2}" ip -f mpls route add 1000 dev lo
|
|
ip netns exec "${ns2}" ip link set lo up
|
|
ip netns exec "${ns2}" sysctl -qw net.mpls.conf.testtun0.input=1
|
|
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.lo.rp_filter=0
|
|
fi
|
|
|
|
# Because packets are decapped by the tunnel they arrive on testtun0 from
|
|
# the IP stack perspective. Ensure reverse path filtering is disabled
|
|
# otherwise we drop the TCP SYN as arriving on testtun0 instead of the
|
|
# expected veth2 (veth2 is where 192.168.1.2 is configured).
|
|
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.all.rp_filter=0
|
|
# rp needs to be disabled for both all and testtun0 as the rp value is
|
|
# selected as the max of the "all" and device-specific values.
|
|
ip netns exec "${ns2}" sysctl -qw net.ipv4.conf.testtun0.rp_filter=0
|
|
ip netns exec "${ns2}" ip link set dev testtun0 up
|
|
if [[ "$expect_tun_fail" == 1 ]]; then
|
|
# This tunnel mode is not supported, so we expect failure.
|
|
echo "test bpf encap with tunnel device decap (expect failure)"
|
|
! client_connect
|
|
else
|
|
echo "test bpf encap with tunnel device decap"
|
|
client_connect
|
|
verify_data
|
|
server_listen
|
|
fi
|
|
|
|
# serverside, use BPF for decap
|
|
ip netns exec "${ns2}" ip link del dev testtun0
|
|
ip netns exec "${ns2}" tc qdisc add dev veth2 clsact
|
|
ip netns exec "${ns2}" tc filter add dev veth2 ingress \
|
|
bpf direct-action object-file ${BPF_FILE} section decap
|
|
echo "test bpf encap with bpf decap"
|
|
client_connect
|
|
verify_data
|
|
|
|
echo OK
|