Files
Frey Alfredsson 9337d2ff8a Adding a basic TC eBPF Qdisc classifier example
This example demonstrates how to write a simple eBPF Qdisc classifier
that classifies flows depending on their destination TCP port. The
example script, runner.sh shows how you can use the eBPF Qdisc
classifier and implement the same functionality using u32. The script
creates two network namespaces called Left and Right, representing two
different hosts. The script then illustrates the classifiers in action
using iperf3 by starting clients on the Left namespace that connect to
iperf3 servers on the Right namespace. The Qdisc classifiers give TCP
ports 8080 and 8081 a high rate limit, while TCP port 8082 represents
all other traffic capped at 20 Mbps.

Signed-off-by: Frey Alfredsson <freysteinn@freysteinn.com>
2021-03-17 02:26:58 +01:00

104 lines
2.9 KiB
Bash
Executable File

#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# Copyright 2021 Frey Alfredsson <freysteinn@freysteinn.com>
set -o errexit
set -o nounset
### Configuration
IP="ip"
TC="tc"
# Left and right IPs
L_IP=172.16.16.10
R_IP=172.16.16.20
L_CIDR="${L_IP}/24"
R_CIDR="${R_IP}/24"
LIMIT=100mbit
START_RATE=5mbit
P8080_LIMIT=80mbit
P8081_LIMIT=40mbit
DEFAULT_LIMIT=20mbit
### Constants
L_NS="left"
R_NS="right"
L_DEV="$L_NS-veth"
R_DEV="$R_NS-veth"
### Helper functions
function filter-help() {
cat <<-EOF
Usage: [<bpf> | <u32>]
Runs an example that either uses an eBPF based Qdisc filter or an u32
filter to rate limit traffic destined for TCP ports 8080 and 8081. It
relies on iperf3 to demonstrates the functionality.
The following are mandatory arguments. Without them prints this help.
u32 Runs the example with the u32 Qdisc filter
bpf Runs the example with the bpf Qdisc filterdiff
Please look at the script's source code to see how the examples differ.
EOF
}
### Script main
if [ $# -ne 1 ] || [[ "${1-}" != "bpf" && "${1-}" != "u32" ]]; then
filter-help
exit 1
fi
mode="$1"
echo "Starting setup"
# Remove network namespaces if this is the second run
$IP netns delete "$L_NS" &> /dev/null || true
$IP netns delete "$R_NS" &> /dev/null || true
# Create network namespaces
$IP netns add "$L_NS"
$IP netns add "$R_NS"
# Create connected virtual nics
$IP link add "$L_DEV" type veth peer "$R_DEV"
# Add the virtual nics to the network namespaces
$IP link set "$L_DEV" netns "$L_NS"
$IP link set "$R_DEV" netns "$R_NS"
# Add IP addresses to links
$IP -netns "$L_NS" addr add "$L_CIDR" dev "$L_DEV"
$IP -netns "$R_NS" addr add "$R_CIDR" dev "$R_DEV"
# Enable links
$IP -netns "$L_NS" link set "$L_DEV" up
$IP -netns "$R_NS" link set "$R_DEV" up
# Setting up the qdiscs on Left
$TC -netns "$L_NS" qdisc add dev "$L_DEV" root handle 1:0 htb default 30
TC_CLASS_ADD="$TC -netns $L_NS class add dev $L_DEV parent"
$TC_CLASS_ADD 1:0 classid 1:1 htb rate "$LIMIT"
$TC_CLASS_ADD 1:1 classid 1:10 htb rate "$START_RATE" ceil "$P8080_LIMIT"
$TC_CLASS_ADD 1:1 classid 1:20 htb rate "$START_RATE" ceil "$P8081_LIMIT"
$TC_CLASS_ADD 1:1 classid 1:30 htb rate "$START_RATE" ceil "$DEFAULT_LIMIT"
# Setup filters
if [ "$mode" == "bpf" ]; then
$TC -netns $L_NS filter add dev $L_DEV protocol ip parent 1:0 \
bpf obj filter.o classid 1: direct-action
else
U32="$TC -netns $L_NS filter add dev $L_DEV protocol ip parent 1:0 prio 1 u32"
$U32 match ip dport 8080 FFFF flowid 1:10
$U32 match ip dport 8081 FFFF flowid 1:20
fi
# Setup iperf3
echo "Starting iperf3"
$IP netns exec "$R_NS" iperf3 -s -p 8080 &> /dev/null &
$IP netns exec "$R_NS" iperf3 -s -p 8081 &> /dev/null &
$IP netns exec "$R_NS" iperf3 -s -p 8082 &> /dev/null &
sleep 1
$IP netns exec "$L_NS" iperf3 -t 4 -c "$R_IP" -p 8080
$IP netns exec "$L_NS" iperf3 -t 4 -c "$R_IP" -p 8081
$IP netns exec "$L_NS" iperf3 -t 4 -c "$R_IP" -p 8082