From: Dave Taht <dave.t...@bufferbloat.net> This adds support for the bufferbloat project's "Smart Queue Management" (SQM) system, which improves over openwrt's qos-scripts in the following ways
+ Uses HTB with two models for managing traffic a simplest one that merely uses fq_codel, and a three tier one that does some basic and tunable packet prioritization. + Works with ipv6 and ipv4 correctly (unlike qos-scripts) + extensive support for fixing ADSL and PPOe framing problems + Partial support for key diffserv markings + highly tuned fq_codel implementation especially for low bandwidths + Tested heavily on cable modems and on dsl devices It is a disimprovement in that: - There are no built-in tricks for doing l7 classification, or other forms of packet inspection. - We haven't explored hfsc all that much, prefering to rely on the predictable behavior of htb + fq_codel for everything - And there is support for a few qdiscs that are not in the linux kernel mainline that remain experimental. --- net/sqm-scripts/Makefile | 48 +++ net/sqm-scripts/files/etc/config/sqm | 11 + net/sqm-scripts/files/etc/init.d/sqm | 23 ++ net/sqm-scripts/files/usr/lib/sqm/functions.sh | 335 ++++++++++++++++++++ net/sqm-scripts/files/usr/lib/sqm/run.sh | 67 ++++ net/sqm-scripts/files/usr/lib/sqm/simple.qos | 187 +++++++++++ net/sqm-scripts/files/usr/lib/sqm/simple.qos.help | 1 + net/sqm-scripts/files/usr/lib/sqm/simplest.qos | 84 +++++ .../files/usr/lib/sqm/simplest.qos.help | 1 + net/sqm-scripts/files/usr/lib/sqm/stop.sh | 22 ++ 10 files changed, 779 insertions(+) create mode 100644 net/sqm-scripts/Makefile create mode 100644 net/sqm-scripts/files/etc/config/sqm create mode 100755 net/sqm-scripts/files/etc/init.d/sqm create mode 100644 net/sqm-scripts/files/usr/lib/sqm/functions.sh create mode 100755 net/sqm-scripts/files/usr/lib/sqm/run.sh create mode 100755 net/sqm-scripts/files/usr/lib/sqm/simple.qos create mode 100644 net/sqm-scripts/files/usr/lib/sqm/simple.qos.help create mode 100755 net/sqm-scripts/files/usr/lib/sqm/simplest.qos create mode 100644 net/sqm-scripts/files/usr/lib/sqm/simplest.qos.help create mode 100755 net/sqm-scripts/files/usr/lib/sqm/stop.sh diff --git a/net/sqm-scripts/Makefile b/net/sqm-scripts/Makefile new file mode 100644 index 0000000..1c92354 --- /dev/null +++ b/net/sqm-scripts/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (C) 2006-2011 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=sqm-scripts +PKG_VERSION:=5 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/sqm-scripts + SECTION:=net + CATEGORY:=Base system + DEPENDS:=+tc +kmod-sched +kmod-ifb +iptables +iptables-mod-filter +iptables-mod-ipopt +iptables-mod-conntrack-extra + TITLE:=SQM Scripts + PKGARCH:=all +endef + +define Package/sqm-scripts/description + A set of scripts that does simple SQM configuration. +endef + +define Package/sqm-scripts/conffiles +/etc/config/sqm +endef + +define Build/Prepare +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/sqm-scripts/install + $(INSTALL_DIR) $(1) + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,sqm-scripts)) diff --git a/net/sqm-scripts/files/etc/config/sqm b/net/sqm-scripts/files/etc/config/sqm new file mode 100644 index 0000000..547d321 --- /dev/null +++ b/net/sqm-scripts/files/etc/config/sqm @@ -0,0 +1,11 @@ + +config queue 'ge00' + option enabled '0' + option interface 'ge00' + option download '20000' + option upload '4000' + option qdisc 'fq_codel' + option script 'simple.qos' + option qdisc_advanced '0' + option linklayer 'none' + diff --git a/net/sqm-scripts/files/etc/init.d/sqm b/net/sqm-scripts/files/etc/init.d/sqm new file mode 100755 index 0000000..70307a6 --- /dev/null +++ b/net/sqm-scripts/files/etc/init.d/sqm @@ -0,0 +1,23 @@ +#!/bin/sh /etc/rc.common + +START=50 + +reload() +{ +/usr/lib/sqm/run.sh +} + +restart() +{ +reload +} + +start() +{ +reload +} + +stop() +{ +/usr/lib/sqm/run.sh stop +} \ No newline at end of file diff --git a/net/sqm-scripts/files/usr/lib/sqm/functions.sh b/net/sqm-scripts/files/usr/lib/sqm/functions.sh new file mode 100644 index 0000000..576af6d --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/functions.sh @@ -0,0 +1,335 @@ + +insmod() { + lsmod | grep -q ^$1 || $INSMOD $1 +} + +ipt() { + d=`echo $* | sed s/-A/-D/g` + [ "$d" != "$*" ] && { + iptables $d > /dev/null 2>&1 + ip6tables $d > /dev/null 2>&1 + } + iptables $* > /dev/null 2>&1 + ip6tables $* > /dev/null 2>&1 +} + +do_modules() { + insmod act_ipt + insmod sch_$QDISC + insmod sch_ingress + insmod act_mirred + insmod cls_fw + insmod sch_htb +} + +# You need to jiggle these parameters. Note limits are tuned towards a <10Mbit uplink <60Mbup down + +[ -z "$UPLINK" ] && UPLINK=2302 +[ -z "$DOWNLINK" ] && DOWNLINK=14698 +[ -z "$DEV" ] && DEV=ifb0 +[ -z "$QDISC" ] && QDISC=fq_codel +[ -z "$IFACE" ] && IFACE=ge00 +[ -z "$LLAM" ] && LLAM="tc_stab" +[ -z "$LINKLAYER" ] && LINKLAYER="none" +[ -z "$OVERHEAD" ] && OVERHEAD=0 +[ -z "$STAB_MTU" ] && STAB_MTU=2047 +[ -z "$STAB_MPU" ] && STAB_MPU=0 +[ -z "$STAB_TSIZE" ] && STAB_TSIZE=512 +[ -z "$AUTOFLOW" ] && AUTOFLOW=0 +[ -z "$LIMIT" ] && LIMIT=1001 # sane global default for *LIMIT for fq_codel on a small memory device +[ -z "$ILIMIT" ] && ILIMIT= +[ -z "$ELIMIT" ] && ELIMIT= +[ -z "$ITARGET" ] && ITARGET= +[ -z "$ETARGET" ] && ETARGET= +[ -z "$IECN" ] && IECN="ECN" +[ -z "$EECN" ] && EECN="NOECN" +[ -z "$IQDISC_OPTS" ] && IQDISC_OPTS="" +[ -z "$EQDISC_OPTS" ] && EQDISC_OPTS="" +[ -z "$TC" ] && TC=`which tc` +# [ -z "$TC" ] && TC="logger tc"# this redirects all tc calls into the log +[ -z "$INSMOD" ] && INSMOD=`which insmod` +[ -z "TARGET" ] && TARGET="5ms" +[ -z "SQUASH_INGRESS" ] && SQUASH_INGRESS=1 + +#logger "iqdisc opts: ${iqdisc_opts}" +#logger "eqdisc opts: ${eqdisc_opts}" + +#logger "LLAM: ${LLAM}" +#logger "LINKLAYER: ${LINKLAYER}" + +get_htb_adsll_string() { + ADSLL="" + if [ "$LLAM" = "htb_private" -a "$LINKLAYER" != "none" ]; + then + # HTB defaults to MTU 1600 and an implicit fixed TSIZE of 256, but HTB as of around 3.10.0 + # does not actually use a table in the kernel + ADSLL="mpu ${STAB_MPU} linklayer ${LINKLAYER} overhead ${OVERHEAD} mtu ${STAB_MTU}" + logger "ADSLL: ${ADSLL}" + fi + echo ${ADSLL} +} + +get_stab_string() { + STABSTRING="" + if [ "${LLAM}" = "tc_stab" -a "$LINKLAYER" != "none" ]; + then + STABSTRING="stab mtu ${STAB_MTU} tsize ${STAB_TSIZE} mpu ${STAB_MPU} overhead ${OVERHEAD} linklayer ${LINKLAYER}" + logger "STAB: ${STABSTRING}" + fi + echo ${STABSTRING} +} + +sqm_stop() { + $TC qdisc del dev $IFACE ingress + $TC qdisc del dev $IFACE root + $TC qdisc del dev $DEV root +} + +# Note this has side effects on the prio variable +# and depends on the interface global too + +fc() { + $TC filter add dev $interface protocol ip parent $1 prio $prio u32 match ip tos $2 0xfc classid $3 + prio=$(($prio + 1)) + $TC filter add dev $interface protocol ipv6 parent $1 prio $prio u32 match ip6 priority $2 0xfc classid $3 + prio=$(($prio + 1)) +} + +# FIXME: actually you need to get the underlying MTU on PPOE thing + +get_mtu() { + BW=$2 + F=`cat /sys/class/net/$1/mtu` + if [ -z "$F" ] + then + F=1500 + fi + if [ $BW -gt 20000 ] + then + F=$(($F * 2)) + fi + if [ $BW -gt 30000 ] + then + F=$(($F * 2)) + fi + if [ $BW -gt 40000 ] + then + F=$(($F * 2)) + fi + if [ $BW -gt 50000 ] + then + F=$(($F * 2)) + fi + if [ $BW -gt 60000 ] + then + F=$(($F * 2)) + fi + if [ $BW -gt 80000 ] + then + F=$(($F * 2)) + fi + echo $F +} + +# FIXME should also calculate the limit +# Frankly I think Xfq_codel can pretty much always run with high numbers of flows +# now that it does fate sharing +# But right now I'm trying to match the ns2 model behavior better +# So SET the autoflow variable to 1 if you want the cablelabs behavior + +get_flows() { + if [ "$AUTOFLOW" -eq "1" ] + then + FLOWS=8 + [ $1 -gt 999 ] && FLOWS=16 + [ $1 -gt 2999 ] && FLOWS=32 + [ $1 -gt 7999 ] && FLOWS=48 + [ $1 -gt 9999 ] && FLOWS=64 + [ $1 -gt 19999 ] && FLOWS=128 + [ $1 -gt 39999 ] && FLOWS=256 + [ $1 -gt 69999 ] && FLOWS=512 + [ $1 -gt 99999 ] && FLOWS=1024 + case $QDISC in + codel|ns2_codel|pie|*fifo|pfifo_fast) ;; + fq_codel|*fq_codel|sfq) echo flows $FLOWS ;; + esac + fi +} + +# set the target parameter, also try to only take well formed inputs +# Note, the link bandwidth in the current direction (ingress or egress) +# is required to adjust the target for slow links +get_target() { + local CUR_TARGET=${1} + local CUR_LINK_KBPS=${2} + [ ! -z "$CUR_TARGET" ] && logger "cur_target: ${CUR_TARGET} cur_bandwidth: ${CUR_LINK_KBPS}" + CUR_TARGET_STRING= + # either e.g. 100ms or auto + CUR_TARGET_VALUE=$( echo ${CUR_TARGET} | grep -o -e \^'[[:digit:]]\+' ) + CUR_TARGET_UNIT=$( echo ${CUR_TARGET} | grep -o -e '[[:alpha:]]\+'\$ ) +# [ ! -z "$CUR_TARGET" ] && logger "CUR_TARGET_VALUE: $CUR_TARGET_VALUE" +# [ ! -z "$CUR_TARGET" ] && logger "CUR_TARGET_UNIT: $CUR_TARGET_UNIT" + + AUTO_TARGET= + UNIT_VALID= + + case $QDISC in + *codel|*pie) + if [ ! -z "${CUR_TARGET_VALUE}" -a ! -z "${CUR_TARGET_UNIT}" ]; + then + case ${CUR_TARGET_UNIT} in + # permissible units taken from: tc_util.c get_time() + s|sec|secs|ms|msec|msecs|us|usec|usecs) + CUR_TARGET_STRING="target ${CUR_TARGET_VALUE}${CUR_TARGET_UNIT}" + UNIT_VALID="1" + ;; + esac + fi + case ${CUR_TARGET_UNIT} in + auto|Auto|AUTO) + if [ ! -z "${CUR_LINK_KBPS}" ]; + then + TMP_TARGET_US=$( adapt_target_to_slow_link $CUR_LINK_KBPS ) + TMP_INTERVAL_STRING=$( adapt_interval_to_slow_link $TMP_TARGET_US ) + CUR_TARGET_STRING="target ${TMP_TARGET_US}us ${TMP_INTERVAL_STRING}" + AUTO_TARGET="1" + else + logger "required link bandwidth in kbps not passed to get_target()." + fi + ;; + esac + if [ ! -z "${CUR_TARGET}" ]; + then + if [ -z "${CUR_TARGET_VALUE}" -o -z "${UNIT_VALID}" ]; + then + [ -z "$AUTO_TARGET" ] && logger "${CUR_TARGET} is not a well formed tc target specifier; e.g.: 5ms (or s, us), or the string auto." + fi + fi + ;; + esac +# logger "target: ${CUR_TARGET_STRING}" + echo $CUR_TARGET_STRING +} + +# for low bandwidth links fq_codels default target of 5ms does not work too well +# so increase target for slow links (note below roughly 2500kbps a single packet will \ +# take more than 5 ms to be tansfered over the wire) +adapt_target_to_slow_link() { + CUR_LINK_KBPS=$1 + CUR_EXTENDED_TARGET_US= + MAX_PAKET_DELAY_IN_US_AT_1KBPS=$(( 1000 * 1000 *1540 * 8 / 1000 )) + CUR_EXTENDED_TARGET_US=$(( ${MAX_PAKET_DELAY_IN_US_AT_1KBPS} / ${CUR_LINK_KBPS} )) # note this truncates the decimals + # do not change anything for fast links + [ "$CUR_EXTENDED_TARGET_US" -lt 5000 ] && CUR_EXTENDED_TARGET_US=5000 + case ${QDISC} in + *codel|pie) + echo "${CUR_EXTENDED_TARGET_US}" + ;; + esac +} + +# codel looks at a whole interval to figure out wether observed latency stayed below target +# if target >= interval that will not work well, so increase interval by the same amonut that target got increased +adapt_interval_to_slow_link() { + CUR_TARGET_US=$1 + case ${QDISC} in + *codel) + CUR_EXTENDED_INTERVAL_US=$(( (100 - 5) * 1000 + ${CUR_TARGET_US} )) + echo "interval ${CUR_EXTENDED_INTERVAL_US}us" + ;; + pie) + ## not sure if pie needs this, probably not + #CUR_EXTENDED_TUPDATE_US=$(( (30 - 20) * 1000 + ${CUR_TARGET_US} )) + #echo "tupdate ${CUR_EXTENDED_TUPDATE_US}us" + ;; + esac +} + + +# set quantum parameter if available for this qdisc +get_quantum() { + case $QDISC in + *fq_codel|fq_pie|drr) echo quantum $1 ;; + *) ;; + esac +} + +# only show limits to qdiscs that can handle them... +# Note that $LIMIT contains the default limit +get_limit() { + CURLIMIT=$1 + case $QDISC in + *codel|*pie|pfifo_fast|sfq|pfifo) [ -z ${CURLIMIT} ] && CURLIMIT=${LIMIT} # use the global default limit + ;; + bfifo) [ -z "$CURLIMIT" ] && [ ! -z "$LIMIT" ] && CURLIMIT=$(( ${LIMIT} * $( cat /sys/class/net/${IFACE}/mtu ) )) # bfifo defaults to txquelength * MTU, + ;; + *) logger "${QDISC} does not support a limit" + ;; + esac + logger "get_limit: $1 CURLIMIT: ${CURLIMIT}" + + if [ ! -z "$CURLIMIT" ] + then + echo "limit ${CURLIMIT}" + fi +} + +get_ecn() { + CURECN=$1 + #logger CURECN: $CURECN + case ${CURECN} in + ECN) + case $QDISC in + *codel|*pie|*red) + CURECN=ecn + ;; + *) + CURECN="" + ;; + esac + ;; + NOECN) + case $QDISC in + *codel|*pie|*red) + CURECN=noecn + ;; + *) + CURECN="" + ;; + esac + ;; + *) + logger "ecn value $1 not handled" + ;; + esac + #logger "get_ECN: $1 CURECN: ${CURECN} IECN: ${IECN} EECN: ${EECN}" + echo ${CURECN} + +} + +# This could be a complete diffserv implementation + +diffserv() { + +interface=$1 +prio=1 + +# Catchall + +$TC filter add dev $interface parent 1:0 protocol all prio 999 u32 \ + match ip protocol 0 0x00 flowid 1:12 + +# Find the most common matches fast + +fc 1:0 0x00 1:12 # BE +fc 1:0 0x20 1:13 # CS1 +fc 1:0 0x10 1:11 # IMM +fc 1:0 0xb8 1:11 # EF +fc 1:0 0xc0 1:11 # CS3 +fc 1:0 0xe0 1:11 # CS6 +fc 1:0 0x90 1:11 # AF42 (mosh) + +# Arp traffic +$TC filter add dev $interface parent 1:0 protocol arp prio $prio handle 1 fw classid 1:11 +prio=$(($prio + 1)) +} diff --git a/net/sqm-scripts/files/usr/lib/sqm/run.sh b/net/sqm-scripts/files/usr/lib/sqm/run.sh new file mode 100755 index 0000000..f46b1d6 --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/run.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +. /lib/functions.sh + +STOP=$1 +ACTIVE_STATE_FILE_DIR="/var/run/SQM" +mkdir -p ${ACTIVE_STATE_FILE_DIR} + +config_load sqm + +IFB_NUM=0 + +run_simple_qos() { + local section="$1" + export IFACE=$(config_get "$section" interface) + ACTIVE_STATE_FILE_FQN="${ACTIVE_STATE_FILE_DIR}/SQM_active_on_${IFACE}" # this marks interfaces as active with SQM + [ -f "${ACTIVE_STATE_FILE_FQN}" ] && logger "${ACTIVE_STATE_FILE_FQN}" + + + if [ $(config_get "$section" enabled) -ne 1 ]; + then + if [ -f "${ACTIVE_STATE_FILE_FQN}" ]; + then + local SECTION_STOP="stop" # it seems the user just de-selected enable, so stop the active SQM + else + return 0 # since SQM is not active on the current interface nothing to do here + fi + fi + + export UPLINK=$(config_get "$section" upload) + export DOWNLINK=$(config_get "$section" download) + export LLAM=$(config_get "$section" linklayer_adaptation_mechanism) + export LINKLAYER=$(config_get "$section" linklayer) + export OVERHEAD=$(config_get "$section" overhead) + export STAB_MTU=$(config_get "$section" tcMTU) + export STAB_TSIZE=$(config_get "$section" tcTSIZE) + export STAB_MPU=$(config_get "$section" tcMPU) + export ILIMIT=$(config_get "$section" ilimit) + export ELIMIT=$(config_get "$section" elimit) + export ITARGET=$(config_get "$section" itarget) + export ETARGET=$(config_get "$section" etarget) + export IECN=$(config_get "$section" ingress_ecn) + export EECN=$(config_get "$section" egress_ecn) + export IQDISC_OPTS=$(config_get "$section" iqdisc_opts) + export EQDISC_OPTS=$(config_get "$section" eqdisc_opts) + export TARGET=$(config_get "$section" target) + export SQUASH_INGRESS=$(config_get "$section" squash_ingress) + + export DEV="ifb${IFB_NUM}" + IFB_NUM=$(expr $IFB_NUM + 1) + + export QDISC=$(config_get "$section" qdisc) + export SCRIPT=/usr/lib/sqm/$(config_get "$section" script) + + if [ "$STOP" == "stop" -o "$SECTION_STOP" == "stop" ]; + then + /usr/lib/sqm/stop.sh + [ -f ${ACTIVE_STATE_FILE_FQN} ] && rm ${ACTIVE_STATE_FILE_FQN} # conditional to avoid errors ACTIVE_STATE_FILE_FQN does not exist anymore + $(config_set "$section" enabled 0) # this does not save to the config file only to the loaded memory representation + logger "SQM qdiscs on ${IFACE} removed" + return 0 + fi + logger "Queue Setup Script: ${SCRIPT}" + [ -x "$SCRIPT" ] && { $SCRIPT ; touch ${ACTIVE_STATE_FILE_FQN}; } +} + +config_foreach run_simple_qos diff --git a/net/sqm-scripts/files/usr/lib/sqm/simple.qos b/net/sqm-scripts/files/usr/lib/sqm/simple.qos new file mode 100755 index 0000000..ae4fb5a --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/simple.qos @@ -0,0 +1,187 @@ +#!/bin/sh +# Cero3 Shaper +# A 3 bin tc_codel and ipv6 enabled shaping script for +# ethernet gateways + +# Copyright (C) 2012 Michael D Taht +# GPLv2 + +# Compared to the complexity that debloat had become +# this cleanly shows a means of going from diffserv marking +# to prioritization using the current tools (ip(6)tables +# and tc. I note that the complexity of debloat exists for +# a reason, and it is expected that script is run first +# to setup various other parameters such as BQL and ethtool. +# (And that the debloat script has setup the other interfaces) + +# You need to jiggle these parameters. Note limits are tuned towards a <10Mbit uplink <60Mbup down + +. /usr/lib/sqm/functions.sh + +ipt_setup() { + +ipt -t mangle -N QOS_MARK_${IFACE} + +ipt -t mangle -A QOS_MARK_${IFACE} -j MARK --set-mark 0x2 +# You can go further with classification but... +ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS1 -j MARK --set-mark 0x3 +ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class CS6 -j MARK --set-mark 0x1 +ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class EF -j MARK --set-mark 0x1 +ipt -t mangle -A QOS_MARK_${IFACE} -m dscp --dscp-class AF42 -j MARK --set-mark 0x1 +ipt -t mangle -A QOS_MARK_${IFACE} -m tos --tos Minimize-Delay -j MARK --set-mark 0x1 + +# and it might be a good idea to do it for udp tunnels too + +# Turn it on. Preserve classification if already performed + +ipt -t mangle -A POSTROUTING -o $DEV -m mark --mark 0x00 -g QOS_MARK_${IFACE} +ipt -t mangle -A POSTROUTING -o $IFACE -m mark --mark 0x00 -g QOS_MARK_${IFACE} + +# The Syn optimization was nice but fq_codel does it for us +# ipt -t mangle -A PREROUTING -i s+ -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 0x01 +# Not sure if this will work. Encapsulation is a problem period + +ipt -t mangle -A PREROUTING -i vtun+ -p tcp -j MARK --set-mark 0x2 # tcp tunnels need ordering + +# Emanating from router, do a little more optimization +# but don't bother with it too much. + +ipt -t mangle -A OUTPUT -p udp -m multiport --ports 123,53 -j DSCP --set-dscp-class AF42 + +#Not clear if the second line is needed +#ipt -t mangle -A OUTPUT -o $IFACE -g QOS_MARK_${IFACE} + +} + + +# TC rules + +egress() { + +CEIL=${UPLINK} +PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty +BE_RATE=`expr $CEIL / 6` # Min for best effort +BK_RATE=`expr $CEIL / 6` # Min for background +BE_CEIL=`expr $CEIL - 16` # A little slop at the top + +LQ="quantum `get_mtu $IFACE $CEIL`" + +$TC qdisc del dev $IFACE root 2> /dev/null +$TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 12 +$TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit `get_htb_adsll_string` +$TC class add dev $IFACE parent 1:1 classid 1:10 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit prio 0 `get_htb_adsll_string` +$TC class add dev $IFACE parent 1:1 classid 1:11 htb $LQ rate 128kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string` +$TC class add dev $IFACE parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit prio 2 `get_htb_adsll_string` +$TC class add dev $IFACE parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit prio 3 `get_htb_adsll_string` + +$TC qdisc add dev $IFACE parent 1:11 handle 110: $QDISC `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${PRIO_RATE}` ${EQDISC_OPTS} +$TC qdisc add dev $IFACE parent 1:12 handle 120: $QDISC `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BE_RATE}` ${EQDISC_OPTS} +$TC qdisc add dev $IFACE parent 1:13 handle 130: $QDISC `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${EQDISC_OPTS} + + +# Need a catchall rule + +$TC filter add dev $IFACE parent 1:0 protocol all prio 999 u32 \ + match ip protocol 0 0x00 flowid 1:12 + +# FIXME should probably change the filter here to do pre-nat + +$TC filter add dev $IFACE parent 1:0 protocol ip prio 1 handle 1 fw classid 1:11 +$TC filter add dev $IFACE parent 1:0 protocol ip prio 2 handle 2 fw classid 1:12 +$TC filter add dev $IFACE parent 1:0 protocol ip prio 3 handle 3 fw classid 1:13 + +# ipv6 support. Note that the handle indicates the fw mark bucket that is looked for + +$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 4 handle 1 fw classid 1:11 +$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 5 handle 2 fw classid 1:12 +$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 6 handle 3 fw classid 1:13 + +# Arp traffic + +$TC filter add dev $IFACE parent 1:0 protocol arp prio 7 handle 1 fw classid 1:11 + +# ICMP traffic - Don't impress your friends. Deoptimize to manage ping floods +# better instead + +$TC filter add dev $IFACE parent 1:0 protocol ip prio 8 \ + u32 match ip protocol 1 0xff flowid 1:13 + +$TC filter add dev $IFACE parent 1:0 protocol ipv6 prio 9 \ + u32 match ip protocol 1 0xff flowid 1:13 + +} + +ingress() { + +CEIL=$DOWNLINK +PRIO_RATE=`expr $CEIL / 3` # Ceiling for prioirty +BE_RATE=`expr $CEIL / 6` # Min for best effort +BK_RATE=`expr $CEIL / 6` # Min for background +BE_CEIL=`expr $CEIL - 16` # A little slop at the top + +LQ="quantum `get_mtu $IFACE $CEIL`" + +$TC qdisc del dev $IFACE handle ffff: ingress 2> /dev/null +$TC qdisc add dev $IFACE handle ffff: ingress + +$TC qdisc del dev $DEV root 2> /dev/null +$TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 12 +$TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit `get_htb_adsll_string` +$TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${CEIL}kbit ceil ${CEIL}kbit prio 0 `get_htb_adsll_string` +$TC class add dev $DEV parent 1:1 classid 1:11 htb $LQ rate 32kbit ceil ${PRIO_RATE}kbit prio 1 `get_htb_adsll_string` +$TC class add dev $DEV parent 1:1 classid 1:12 htb $LQ rate ${BE_RATE}kbit ceil ${BE_CEIL}kbit prio 2 `get_htb_adsll_string` +$TC class add dev $DEV parent 1:1 classid 1:13 htb $LQ rate ${BK_RATE}kbit ceil ${BE_CEIL}kbit prio 3 `get_htb_adsll_string` + +# I'd prefer to use a pre-nat filter but that causes permutation... + +$TC qdisc add dev $DEV parent 1:11 handle 110: $QDISC `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 500` `get_flows ${PRIO_RATE}` ${IQDISC_OPTS} +$TC qdisc add dev $DEV parent 1:12 handle 120: $QDISC `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 1500` `get_flows ${BE_RATE}` ${IQDISC_OPTS} +$TC qdisc add dev $DEV parent 1:13 handle 130: $QDISC `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 300` `get_flows ${BK_RATE}` ${IQDISC_OPTS} + +diffserv $DEV + +ifconfig $DEV up + +# redirect all IP packets arriving in $IFACE to ifb0 + +$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV + +} + +do_modules +ipt_setup + +if [ "$UPLINK" -ne 0 ]; +then + egress + logger "egress shaping activated" +else + logger "egress shaping deactivated" + tc qdisc del dev $IFACE root 2> /dev/null +fi +if [ "$DOWNLINK" -ne 0 ]; +then + ingress + logger "ingress shaping activated" +else + logger "ingress shaping deactivated" + tc qdisc del dev $DEV root 2> /dev/null + tc qdisc del dev $IFACE ingress 2> /dev/null +fi + + + +# References: +# This alternate shaper attempts to go for 1/u performance in a clever way +# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD + +# Comments +# This does the right thing with ipv6 traffic. +# It also tries to leverage diffserv to some sane extent. In particular, +# the 'priority' queue is limited to 33% of the total, so EF, and IMM traffic +# cannot starve other types. The rfc suggested 30%. 30% is probably +# a lot in today's world. + +# Flaws +# Many! diff --git a/net/sqm-scripts/files/usr/lib/sqm/simple.qos.help b/net/sqm-scripts/files/usr/lib/sqm/simple.qos.help new file mode 100644 index 0000000..b059601 --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/simple.qos.help @@ -0,0 +1 @@ +BW-limited three-tier prioritisation scheme with fq_codel on each queue. (default) diff --git a/net/sqm-scripts/files/usr/lib/sqm/simplest.qos b/net/sqm-scripts/files/usr/lib/sqm/simplest.qos new file mode 100755 index 0000000..46c7634 --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/simplest.qos @@ -0,0 +1,84 @@ +#!/bin/sh +# Cero3 Simple Shaper +# A 1 bin tc_codel and ipv6 enabled shaping script for +# ethernet gateways. This is nearly the simplest possible + +# Copyright (C) 2013 Michael D Taht +# GPLv2 +logger "Starting simplest.qos" + +. /usr/lib/sqm/functions.sh + + + + +egress() { + +LQ="quantum `get_mtu $IFACE ${UPLINK}`" + +$TC qdisc del dev $IFACE root 2>/dev/null +$TC qdisc add dev $IFACE root handle 1: `get_stab_string` htb default 10 +$TC class add dev $IFACE parent 1: classid 1:1 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit `get_htb_adsll_string` +$TC class add dev $IFACE parent 1:1 classid 1:10 htb $LQ rate ${UPLINK}kbit ceil ${UPLINK}kbit prio 0 `get_htb_adsll_string` +$TC qdisc add dev $IFACE parent 1:10 handle 110: $QDISC `get_limit ${ELIMIT}` `get_target "${ETARGET}" ${UPLINK}` `get_ecn ${EECN}` `get_flows ${UPLINK}` ${EQDISC_OPTS} + +} + + +ingress() { +logger "ingress" +$TC qdisc del dev $IFACE handle ffff: ingress 2>/dev/null +$TC qdisc add dev $IFACE handle ffff: ingress + +LQ="quantum `get_mtu $IFACE ${DOWNLINK}`" + +$TC qdisc del dev $DEV root 2>/dev/null +$TC qdisc add dev $DEV root handle 1: `get_stab_string` htb default 10 +$TC class add dev $DEV parent 1: classid 1:1 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit `get_htb_adsll_string` +$TC class add dev $DEV parent 1:1 classid 1:10 htb $LQ rate ${DOWNLINK}kbit ceil ${DOWNLINK}kbit prio 0 `get_htb_adsll_string` + +# FIXME: I'd prefer to use a pre-nat filter but we need to detect if nat is on this interface +# AND we need to permute by a random number which we can't do from userspace filters + +# Most high rate flows are REALLY close. This stomps on those harder, but hurts on high rate long distance +#$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC limit $LIMIT $ECN interval 20ms target 3ms `get_flows ${DOWNLINK}` +$TC qdisc add dev $DEV parent 1:10 handle 110: $QDISC `get_limit ${ILIMIT}` `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_flows ${DOWNLINK}` ${IQDISC_OPTS} + +ifconfig $DEV up + +# redirect all IP packets arriving in $IFACE to ifb0 + +$TC filter add dev $IFACE parent ffff: protocol all prio 10 u32 \ + match u32 0 0 flowid 1:1 action mirred egress redirect dev $DEV + +} + +do_modules + +if [ "$UPLINK" -ne 0 ]; +then + egress + logger "egress shaping activated" +else + logger "egress shaping deactivated" + tc qdisc del dev $IFACE root 2> /dev/null +fi +if [ "$DOWNLINK" -ne 0 ]; +then + ingress + logger "ingress shaping activated" +else + logger "ingress shaping deactivated" + tc qdisc del dev $DEV root 2> /dev/null + tc qdisc del dev $IFACE ingress 2> /dev/null +fi + + +# References: +# This alternate shaper attempts to go for 1/u performance in a clever way +# http://git.coverfire.com/?p=linux-qos-scripts.git;a=blob;f=src-3tos.sh;hb=HEAD + +# Comments +# This does the right thing with ipv6 traffic. +# Flaws +# Many! diff --git a/net/sqm-scripts/files/usr/lib/sqm/simplest.qos.help b/net/sqm-scripts/files/usr/lib/sqm/simplest.qos.help new file mode 100644 index 0000000..c359256 --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/simplest.qos.help @@ -0,0 +1 @@ +Simplest possible configuration: HTB rate limiter with your qdisc attached. diff --git a/net/sqm-scripts/files/usr/lib/sqm/stop.sh b/net/sqm-scripts/files/usr/lib/sqm/stop.sh new file mode 100755 index 0000000..0b7f222 --- /dev/null +++ b/net/sqm-scripts/files/usr/lib/sqm/stop.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +. /usr/lib/sqm/functions.sh + +sqm_stop() { + tc qdisc del dev $IFACE ingress 2> /dev/null + tc qdisc del dev $IFACE root 2> /dev/null + tc qdisc del dev $DEV root 2> /dev/null +} + +ipt_stop() { + ipt -t mangle -D POSTROUTING -o $DEV -m mark --mark 0x00 -g QOS_MARK_${IFACE} + ipt -t mangle -D POSTROUTING -o $IFACE -m mark --mark 0x00 -g QOS_MARK_${IFACE} + ipt -t mangle -D PREROUTING -i vtun+ -p tcp -j MARK --set-mark 0x2 + ipt -t mangle -D OUTPUT -p udp -m multiport --ports 123,53 -j DSCP --set-dscp-class AF42 + ipt -t mangle -F QOS_MARK_${IFACE} + ipt -t mangle -X QOS_MARK_${IFACE} +} + + +sqm_stop +ipt_stop \ No newline at end of file -- 1.7.9.5 _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel