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

Reply via email to