diff --git a/src/defaults.sh b/src/defaults.sh index ecb043fd..1ff366ef 100644 --- a/src/defaults.sh +++ b/src/defaults.sh @@ -10,7 +10,7 @@ [ -z "$STAB_MTU" ] && STAB_MTU=2047 [ -z "$STAB_MPU" ] && STAB_MPU=0 [ -z "$STAB_TSIZE" ] && STAB_TSIZE=512 -[ -z "$AUTOFLOW" ] && AUTOFLOW=0 +[ -z "$AUTOFLOW" ] && AUTOFLOW=1 [ -z "$LIMIT" ] && LIMIT=1001 # sane global default for *LIMIT for fq_codel on a small memory device [ -z "$ILIMIT" ] && ILIMIT= [ -z "$ELIMIT" ] && ELIMIT= diff --git a/src/functions.sh b/src/functions.sh index 770ab1f9..3150968a 100644 --- a/src/functions.sh +++ b/src/functions.sh @@ -39,7 +39,10 @@ do_modules() { insmod sch_ingress insmod act_mirred insmod cls_fw + insmod cls_flow + insmod cls_u32 insmod sch_htb + insmod sch_hfsc } @@ -166,7 +169,7 @@ fc_pppoe() { match u16 ${PPP_PROTO_IP6} 0xffff at 6 \ match u16 0x0${2:2:2}0 0x0fc0 at 8 \ flowid $3 - + prio=$(($prio + 1)) } @@ -177,7 +180,7 @@ fc_pppoe() { get_htb_quantum() { CUR_QUANTUM=$( get_mtu $1 ) BANDWIDTH=$2 - + if [ -z "${CUR_QUANTUM}" ] then CUR_QUANTUM=1500 @@ -221,29 +224,34 @@ get_mtu() { echo ${CUR_MTU} } -# 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 + + if [ "${AUTOFLOW}" -eq "1" ] + then + case $QDISC in + codel|ns2_codel|pie|*fifo|pfifo_fast) ;; + fq_codel|*fq_codel|sfq) echo flows $( get_flows_count ${1} ) ;; + esac + fi + +} + +get_flows_count() { + + 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 ;; + esac + } # set the target parameter, also try to only take well formed inputs @@ -335,7 +343,7 @@ get_target() { 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 )) + 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 @@ -486,3 +494,20 @@ prio=$(($prio + 1)) } + +eth_setup() { + + ethtool -K $IFACE gso off + ethtool -K $IFACE tso off + ethtool -K $IFACE ufo off + ethtool -K $IFACE gro off + + if [ -e /sys/class/net/$IFACE/queues/tx-0/byte_queue_limits ] + then + for i in /sys/class/net/$IFACE/queues/tx-*/byte_queue_limits + do + echo $(( 4 * $( get_mtu ${IFACE} ) )) > $i/limit_max + done + fi + +} diff --git a/src/nxt_routed_hfsc.qos b/src/nxt_routed_hfsc.qos new file mode 100755 index 00000000..3e22df28 --- /dev/null +++ b/src/nxt_routed_hfsc.qos @@ -0,0 +1,146 @@ +#!/bin/sh + +# This script implements a 3 queue traffic classification system on egress and +# single queue on ingress. It is built specifically for NAT/Masquerade gateways. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. + +[ -n "${IFACE}" ] || exit 1 +. ${SQM_LIB_DIR}/defaults.sh || exit 1 + +ipt_setup() { + + ipt -t mangle -F QOS_MARK_${IFACE} + ipt -t mangle -X QOS_MARK_${IFACE} + ipt -t mangle -N QOS_MARK_${IFACE} + + ipt -t mangle -F QOS_RULES_${IFACE} + ipt -t mangle -X QOS_RULES_${IFACE} + ipt -t mangle -N QOS_RULES_${IFACE} + + ipt -t mangle -F QOS_RECLASS_${IFACE} + ipt -t mangle -X QOS_RECLASS_${IFACE} + ipt -t mangle -N QOS_RECLASS_${IFACE} + + ipt -t mangle -A POSTROUTING -o ${IFACE} -g QOS_MARK_${IFACE} + + ipt -t mangle -A QOS_MARK_${IFACE} -j CONNMARK \ + --restore-mark --nfmask ${IPT_MASK} --ctmask ${IPT_MASK} + ipt -t mangle -A QOS_MARK_${IFACE} -m mark --mark 0x00${IPT_MASK_STRING} \ + -j QOS_RULES_${IFACE} + ipt -t mangle -A QOS_MARK_${IFACE} -m mark --mark 0x01${IPT_MASK_STRING} \ + -j QOS_RECLASS_${IFACE} + + ipt -t mangle -A QOS_RULES_${IFACE} -p tcp -m multiport \ + --dports 20,21,22,25,80,110,443,465,993,995 -j MARK --set-mark 0x01${IPT_MASK_STRING} + ipt -t mangle -A QOS_RULES_${IFACE} -p udp -m multiport \ + --dports 53,123 -j MARK --set-mark 0x01${IPT_MASK_STRING} + ipt -t mangle -A QOS_RULES_${IFACE} -p icmp -j MARK --set-mark 0x01${IPT_MASK_STRING} + ipt -t mangle -A QOS_RULES_${IFACE} -m mark --mark 0x00${IPT_MASK_STRING} \ + -j MARK --set-mark 0x03${IPT_MASK_STRING} + ipt -t mangle -A QOS_RULES_${IFACE} -j CONNMARK \ + --save-mark --nfmask ${IPT_MASK} --ctmask ${IPT_MASK} + + ipt -t mangle -A QOS_RECLASS_${IFACE} -p tcp -m connbytes \ + --connbytes 1125: --connbytes-dir original --connbytes-mode bytes \ + -j MARK --set-mark 0x02${IPT_MASK_STRING} + ipt -t mangle -A QOS_RECLASS_${IFACE} -m mark --mark 0x02${IPT_MASK_STRING} -j CONNMARK \ + --save-mark --nfmask ${IPT_MASK} --ctmask ${IPT_MASK} + +} + +egress() { + + BULK=$(( ${UPLINK} * 30 / 100 )) + NORMAL=$(( ${UPLINK} * 70 / 100 )) + MAX=$(( ${UPLINK} * 95 / 100 )) + + $TC qdisc del dev ${IFACE} root 2> /dev/null + $TC qdisc add dev ${IFACE} root handle 1: `get_stab_string` hfsc default 13 + + $TC class add dev ${IFACE} parent 1: classid 1:1 hfsc sc rate ${UPLINK}kbit \ + ul rate ${UPLINK}kbit + + $TC class add dev ${IFACE} parent 1:1 classid 1:11 hfsc rt rate ${MAX}kbit + $TC class add dev ${IFACE} parent 1:1 classid 1:12 hfsc ls rate ${NORMAL}kbit + $TC class add dev ${IFACE} parent 1:1 classid 1:13 hfsc ls rate ${BULK}kbit + + $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 ${MAX}` ${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 ${NORMAL}` ${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 ${BULK}` ${EQDISC_OPTS} + + $TC filter add dev ${IFACE} parent 110: handle 110 protocol all \ + flow hash keys nfct-src,nfct-dst,nfct-proto,nfct-proto-src,nfct-proto-dst \ + divisor `get_flows_count ${MAX}` + $TC filter add dev ${IFACE} parent 120: handle 120 protocol all \ + flow hash keys nfct-src,nfct-dst,nfct-proto,nfct-proto-src,nfct-proto-dst \ + divisor `get_flows_count ${NORMAL}` + $TC filter add dev ${IFACE} parent 130: handle 130 protocol all \ + flow hash keys nfct-src,nfct-dst,nfct-proto,nfct-proto-src,nfct-proto-dst \ + divisor `get_flows_count ${BULK}` + + $TC filter add dev ${IFACE} parent 1:0 protocol all prio 1 u32 \ + match mark 0x01 ${IPT_MASK} flowid 1:11 + $TC filter add dev ${IFACE} parent 1:0 protocol all prio 2 u32 \ + match mark 0x02 ${IPT_MASK} flowid 1:12 + $TC filter add dev ${IFACE} parent 1:0 protocol all prio 2 u32 \ + match mark 0x03 ${IPT_MASK} flowid 1:13 + +} + +ingress() { + + $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` hfsc default 1 + + $TC class add dev ${DEV} parent 1: classid 1:1 hfsc sc rate ${DOWNLINK}kbit \ + ul rate ${DOWNLINK}kbit + + $TC qdisc add dev ${DEV} parent 1:1 handle 11: ${QDISC} `get_limit ${ILIMIT}` \ + `get_target "${ITARGET}" ${DOWNLINK}` `get_ecn ${IECN}` `get_quantum 1540` \ + `get_flows ${DOWNLINK}` ${IQDISC_OPTS} + + $TC filter add dev ${DEV} parent 11: handle 11 protocol all \ + flow hash keys nfct-src,nfct-dst,nfct-proto,nfct-proto-src,nfct-proto-dst \ + divisor `get_flows_count ${DOWNLINK}` + + ifconfig ${DEV} up + + $TC filter add dev ${IFACE} parent ffff: protocol all prio 1 u32 \ + match u32 0 0 action mirred egress redirect dev ${DEV} + +} + +do_modules +eth_setup +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 diff --git a/src/nxt_routed_hfsc.qos.help b/src/nxt_routed_hfsc.qos.help new file mode 100644 index 00000000..111f709d --- /dev/null +++ b/src/nxt_routed_hfsc.qos.help @@ -0,0 +1,2 @@ +Uses a combination of HFSC and FLOW classifier to prioritize typical interactive protocols. +This script is specially designed for clients behind NAT.