#!/bin/sh
. /lib/rcscripts/sh/error.sh
conf=/etc/netd/bandwidth.conf
. $conf || error "Failed to source '$conf'!"
DEFAULT_QDISC=
DEFAULT_QDISC_OPTS=
read DEFAULT_QDISC </proc/sys/net/core/default_qdisc
IFACES=""
if ip link show eth0 > /dev/null 2>& then
IFACES="$IFACES eth0"
fi
if ip link show eth1 >/dev/null 2>& then
IFACES="$IFACES eth1"
fi
for iface in $IFACES; do
mtu=$(ip -o link show $iface)
mtu=${mtu#*mtu[[:blank:]]}
mtu=${mtu%%[[:blank:]]*}
[ "$mtu" ] || error "Could not get mtu for $iface"
eval "MTU_$iface=$mtu"
done
get_default_qdisc_opts() {
local mtu roundup flow_limit
[ $# -gt 0 ] || error "get_default_qdisc_opts: missing iface name argument"
DEFAULT_QDISC_OPTS=
[ "$DEFAULT_QDISC" = fq ] || return 0
[ "$WMEM_MAX" ] || {
WMEM_MAX=$(cat /proc/sys/net/core/wmem_max) ||
error "Failed to read wmem_max"
WMEM_MAX=$(($WMEM_MAX * 2))
}
eval mtu=\$MTU_$1
roundup=10
flow_limit=$(($WMEM_MAX / $mtu))
flow_limit=$(((($flow_limit / $roundup) + 1) * $roundup))
DEFAULT_QDISC_OPTS="flow_limit $flow_limit"
}
tc_default() {
local iface
[ "$DEFAULT_QDISC" ] || return 0
for iface in $IFACES; do
get_default_qdisc_opts $iface
tc qdisc replace dev $iface root $DEFAULT_QDISC $DEFAULT_QDISC_OPTS || return 1
done
}
tc_add_cmd() {
local tc_burst=
[ $# -gt 0 ] || error "tc_add_cmd: missing iface name argument"
eval tc_burst=\$MTU_$1
tc_burst=$(($tc_burst + 100))
if [ $TC_BURST -gt $tc_burst ]; then
tc_burst=$TC_BURST
fi
[ $tc_burst -gt 0 ] || error "No valid burst value"
tc qdisc del dev $1 root 2>/dev/null || :
tc qdisc add dev $1 root handle 1: htb default 10 || return 1
tc class add dev $1 parent 1: classid 1:1 htb rate $TC_RATE || return 1
tc class add dev $1 parent 1:1 classid 1:10 htb rate 100Kbit ceil $TC_RATE\
prio 0 || return 1
tc qdisc add dev $1 parent 1:10 handle 100: tbf rate $TC_RATE burst $tc_burst\
latency 1 || return 1
case $DEFAULT_QDISC in
fq|fq_codel|pfifo_fast)
get_default_qdisc_opts $1
tc qdisc add dev $1 parent 100:1 $DEFAULT_QDISC $DEFAULT_QDISC_OPTS || return 1
;
esac
tc class add dev $1 parent 1:1 classid 1:20 htb rate 100kbit ceil $TC_RATE \
prio 0 || return 1
tc qdisc add dev $1 parent 1:20 tbf rate $TC_RATE burst $tc_burst latency 1s \
|| return 1
tc filter add dev $1 parent 1: protocol ip prio 0 u32 match ip protocol 17 \
0xff flowid 1:20 || return 1
return 0
}
bandwidth_start() {
local rate rate_unit iface changed
rate=${TC_RATE%%[[:alpha:]]*}
rate_unit=${TC_RATE#$rate}
changed=
case $rate_unit in
[Kk][Bb]it)
if [ $rate -ge $LOWER_LIMIT_KBIT ] &&
[ $rate -le $UPPER_LIMIT_KBIT ]; then
changed=y
for iface in $IFACES; do
tc_add_cmd $iface || {
bandwidth_stop
break
}
done
fi
;
[Mm][Bb]it)
if [ $rate -ge $LOWER_LIMIT_MBIT ] &&
[ $rate -le $UPPER_LIMIT_MBIT ]; then
changed=y
for iface in $IFACES; do
tc_add_cmd $iface || {
bandwidth_stop
break
}
done
fi
;
esac
[ "$changed" ] || tc_default
}
bandwidth_stop() {
local iface
for iface in $IFACES; do
tc qdisc del dev $iface root 2>/dev/null || :
done
tc_default
}
case "$1" in
start)
information "Setting traffic control settings"
bandwidth_start
;
stop)
information "Removing traffic control settings"
bandwidth_stop
;
*)
error "Usage: $0 start|stop"
;
esac