1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# This test installs a TC bpf program that throttles a TCP flow
5# with dst port = 9000 down to 5MBps. Then it measures actual
6# throughput of the flow.
7
8BPF_FILE="test_tc_edt.bpf.o"
9if [[ $EUID -ne 0 ]]; then
10	echo "This script must be run as root"
11	echo "FAIL"
12	exit 1
13fi
14
15# check that nc, dd, and timeout are present
16command -v nc >/dev/null 2>&1 || \
17	{ echo >&2 "nc is not available"; exit 1; }
18command -v dd >/dev/null 2>&1 || \
19	{ echo >&2 "nc is not available"; exit 1; }
20command -v timeout >/dev/null 2>&1 || \
21	{ echo >&2 "timeout is not available"; exit 1; }
22
23readonly NS_SRC="ns-src-$(mktemp -u XXXXXX)"
24readonly NS_DST="ns-dst-$(mktemp -u XXXXXX)"
25
26readonly IP_SRC="172.16.1.100"
27readonly IP_DST="172.16.2.100"
28
29cleanup()
30{
31	ip netns del ${NS_SRC}
32	ip netns del ${NS_DST}
33}
34
35trap cleanup EXIT
36
37set -e  # exit on error
38
39ip netns add "${NS_SRC}"
40ip netns add "${NS_DST}"
41ip link add veth_src type veth peer name veth_dst
42ip link set veth_src netns ${NS_SRC}
43ip link set veth_dst netns ${NS_DST}
44
45ip -netns ${NS_SRC} addr add ${IP_SRC}/24  dev veth_src
46ip -netns ${NS_DST} addr add ${IP_DST}/24  dev veth_dst
47
48ip -netns ${NS_SRC} link set dev veth_src up
49ip -netns ${NS_DST} link set dev veth_dst up
50
51ip -netns ${NS_SRC} route add ${IP_DST}/32  dev veth_src
52ip -netns ${NS_DST} route add ${IP_SRC}/32  dev veth_dst
53
54# set up TC on TX
55ip netns exec ${NS_SRC} tc qdisc add dev veth_src root fq
56ip netns exec ${NS_SRC} tc qdisc add dev veth_src clsact
57ip netns exec ${NS_SRC} tc filter add dev veth_src egress \
58	bpf da obj ${BPF_FILE} sec cls_test
59
60
61# start the listener
62ip netns exec ${NS_DST} bash -c \
63	"nc -4 -l -p 9000 >/dev/null &"
64declare -i NC_PID=$!
65sleep 1
66
67declare -ir TIMEOUT=20
68declare -ir EXPECTED_BPS=5000000
69
70# run the load, capture RX bytes on DST
71declare -ir RX_BYTES_START=$( ip netns exec ${NS_DST} \
72	cat /sys/class/net/veth_dst/statistics/rx_bytes )
73
74set +e
75ip netns exec ${NS_SRC} bash -c "timeout ${TIMEOUT} dd if=/dev/zero \
76	bs=1000 count=1000000 > /dev/tcp/${IP_DST}/9000 2>/dev/null"
77set -e
78
79declare -ir RX_BYTES_END=$( ip netns exec ${NS_DST} \
80	cat /sys/class/net/veth_dst/statistics/rx_bytes )
81
82declare -ir ACTUAL_BPS=$(( ($RX_BYTES_END - $RX_BYTES_START) / $TIMEOUT ))
83
84echo $TIMEOUT $ACTUAL_BPS $EXPECTED_BPS | \
85	awk '{printf "elapsed: %d sec; bps difference: %.2f%%\n",
86		$1, ($2-$3)*100.0/$3}'
87
88# Pass the test if the actual bps is within 1% of the expected bps.
89# The difference is usually about 0.1% on a 20-sec test, and ==> zero
90# the longer the test runs.
91declare -ir RES=$( echo $ACTUAL_BPS $EXPECTED_BPS | \
92	 awk 'function abs(x){return ((x < 0.0) ? -x : x)}
93	      {if (abs(($1-$2)*100.0/$2) > 1.0) { print "1" }
94		else { print "0"} }' )
95if [ "${RES}" == "0" ] ; then
96	echo "PASS"
97else
98	echo "FAIL"
99	exit 1
100fi
101