This is what I currently use to keep buffering under control and ensure fairness. It integrates with ifupdown in Debian derived distros (that is, /etc/network/interfaces)
(Edit) PS! I do not know if the vanilla Linode kernel has all the required bits compiled in. I'm using pv-grub to load our own kernel. 3.4 and newer ships with the needed parts, but it might not be enabled.
You can test it directly by running
Code:
IFACE=eth0 IF_EGRESS_RATE=240Mbit ./shaper
Code:
#!/bin/sh
#
# Add fq_codel to all networking devices without any config.
#
# Save as /etc/network/if-up.d/shaper
# chmod 755 /etc/network/if-up.d/shaper
#
# Needs a fairly recent iproute package (from sometime in 2012 IIRC).
# fq_codel and Byte Queue Limits kernel support (mainline since 3.4 I think)
# HFSC shaper kernel support if using egress-rate
# IFB device kernel support if using ingress-redir
#
# Needs kernel supporting fq_codel qdisc, HFSC shaper, and a fairly
# recent iproute package. IFB also needs to be supported in kernel if
# ingress-redir is used.
#
# Support setting a custom egress-rate to avoid excessive buffering when
# it happens upstream of us (say, shaper on a vm host). Otherwise we
# just add as root qdisc.
#
# Avoids wireless devices because they are currently incompatible.
#
# In /etc/network/interfaces
# if no excessive buffering upstream, no config needed. fq_codel is
# attached directly to device.
#
# If excessive buffering upstream - limit our egress by setting a egress-rate:
#
# iface eth0 inet dhcp
# egress-rate 240Mbit
#
# To shape ingress, redirect to a queueing device and set the egress
# limit on that (works only because TCP tries to be nice)
#
# iface eth0 inet dhcp
# ingress-redir ifb0
#
# iface ifb0 inet manual
# egress-rate 500Mbit
#
# Note that the bandwidths must be set low enough to avoid packets
# getting queued in the upstream buffer, typically a little under what
# you're sold.
#
# Other available parameters are:
# egress-target try to keep buffering below this value, default 5ms
# egress-flows fq_codel flow "buckets", default 10240
# egress-ecn do ECN marking when saturating, "yes" to turn on - default off
#
# It can be useful to also turn off TSO, GSO and GRO using ethtool -K
# to improve accuracy (at the cost of some more CPU usage).
#
# Debug (show commands)
set -x
IP=/sbin/ip
TC=/sbin/tc
[ ! -x "$TC" ] || [ ! -x "$IP" ] && exit 0
[ "$IFACE" = "lo" ] && exit 0
# Buggy logic to detect physical device and exclude wireless
[ ! -e "/sys/class/net/$IFACE/device" ] && [ -z "$IF_EGRESS_RATE" ] && exit 0
[ -e "/sys/class/net/$IFACE/wireless" ] && [ -z "$IF_EGRESS_RATE" ] && exit 0
[ -z "$IF_EGRESS_TARGET" ] && IF_EGRESS_TARGET=5ms
[ -z "$IF_EGRESS_FLOWS" ] && IF_EGRESS_FLOWS=10240
# Is ECN useful on egress when we are the source (not forwarding)?
# leave off by default for now.
ecn="noecn"
if [ "$IF_EGRESS_ECN" = "on" ] || [ "$IF_EGRESS_ECN" = "yes" ]; then
ecn="ecn"
fi
# Reset
$TC qdisc del dev $IFACE root 2>/dev/null || true
$TC qdisc del dev $IFACE ingress 2>/dev/null || true
if [ ! -z "$IF_EGRESS_RATE" ]; then
# Bandwidth limiting mode
echo "Setting egress rate of $IFACE to $IF_EGRESS_RATE, target $IF_EGRESS_TARGET, flows $IF_EGRESS_FLOWS"
$TC qdisc add dev $IFACE root handle 1 hfsc default 1
$TC class add dev $IFACE parent 1: classid 1:1 hfsc sc rate $IF_EGRESS_RATE ul rate $IF_EGRESS_RATE
$TC qdisc add dev $IFACE parent 1:1 handle 11: fq_codel target $IF_EGRESS_TARGET flows $IF_EGRESS_FLOWS $ecn
else
# Link-limited mode (default and dont fail interface bringup if it doesnt work)
echo "Setting scheduler of $IFACE to fq_codel, target $IF_EGRESS_TARGET, flows $IF_EGRESS_FLOWS"
$TC qdisc add dev $IFACE root fq_codel target $IF_EGRESS_TARGET flows $IF_EGRESS_FLOWS $ecn || true
fi
# Redir to queueing device
if [ ! -z "$IF_INGRESS_REDIR" ]; then
$IP link set dev $IF_INGRESS_REDIR up
$TC qdisc add dev $IFACE ingress
# Redirect both IPv4 and IPv6..
$TC filter add dev $IFACE parent ffff: protocol ip prio 1 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev $IF_INGRESS_REDIR
$TC filter add dev $IFACE parent ffff: protocol ipv6 prio 2 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev $IF_INGRESS_REDIR
fi