From: Felix Fietkau Date: Fri, 6 Oct 2006 17:09:53 +0000 (+0000) Subject: add the qos-scripts package X-Git-Tag: whiterussian_rc6~114 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=96a60d138ab22df46a38e180e92438930f360f24;p=openwrt%2Fsvn-archive%2Fopenwrt.git add the qos-scripts package SVN-Revision: 4931 --- diff --git a/openwrt/package/Config.in b/openwrt/package/Config.in index dc576182a4..cf502dabb1 100644 --- a/openwrt/package/Config.in +++ b/openwrt/package/Config.in @@ -72,6 +72,7 @@ source "package/ppp/Config.in" source "package/pptp/Config.in" source "package/pptpd/Config.in" source "package/quagga/Config.in" +source "package/qos-scripts/Config.in" source "package/radvd/Config.in" source "package/robocfg/Config.in" source "package/rsync/Config.in" diff --git a/openwrt/package/Makefile b/openwrt/package/Makefile index 0b9c14e00a..93224b0594 100644 --- a/openwrt/package/Makefile +++ b/openwrt/package/Makefile @@ -94,6 +94,7 @@ package-$(BR2_PACKAGE_PPTPD) += pptpd package-$(BR2_PACKAGE_PROCPS) += procps package-$(BR2_PACKAGE_PSMISC) += psmisc package-$(BR2_PACKAGE_QUAGGA) += quagga +package-$(BR2_PACKAGE_QOS_SCRIPTS) += qos-scripts package-$(BR2_PACKAGE_RADVD) += radvd package-$(BR2_COMPILE_RADIUSCLIENT_NG) += radiusclient-ng package-$(BR2_PACKAGE_READLINE) += readline diff --git a/openwrt/package/qos-scripts/Config.in b/openwrt/package/qos-scripts/Config.in new file mode 100644 index 0000000000..0944b3b7dc --- /dev/null +++ b/openwrt/package/qos-scripts/Config.in @@ -0,0 +1,15 @@ +config BR2_PACKAGE_QOS_SCRIPTS + tristate "QoS scripts." + default m if CONFIG_DEVEL + select BR2_PACKAGE_TC + select BR2_PACKAGE_KMOD_SCHED + select BR2_PACKAGE_IPTABLES_MOD_FILTER + select BR2_PACKAGE_IPTABLES_MOD_IPOPT + select BR2_PACKAGE_IPTABLES_MOD_EXTRA + select BR2_PACKAGE_IPTABLES_MOD_CONNTRACK + select BR2_PACKAGE_IPTABLES_MOD_IMQ + help + A set of scripts that abstract QoS configuration + into a simple configuration file supporting stanzas that specify + any number of QoS entries. + diff --git a/openwrt/package/qos-scripts/Makefile b/openwrt/package/qos-scripts/Makefile new file mode 100644 index 0000000000..2f1dfe8e04 --- /dev/null +++ b/openwrt/package/qos-scripts/Makefile @@ -0,0 +1,27 @@ +# $Id: Makefile 3198 2006-02-09 03:21:01Z nbd $ + +include $(TOPDIR)/rules.mk + +PKG_NAME := qos_scripts +PKG_RELEASE := 1 +PKG_VERSION := 0.9.2 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(TOPDIR)/package/rules.mk + +$(eval $(call PKG_template,QOS_SCRIPTS,$(PKG_NAME),$(PKG_VERSION)-$(PKG_RELEASE),$(ARCH))) + +$(PKG_BUILD_DIR)/.prepared: + mkdir -p $@ + touch $@ + +$(PKG_BUILD_DIR)/.built: + cp -a ./files $(PKG_BUILD_DIR)/qos_scripts + touch $@ + +$(IPKG_QOS_SCRIPTS): + chmod -R 755 $(PKG_BUILD_DIR)/qos_scripts/ + cp -a $(PKG_BUILD_DIR)/qos_scripts/* $(IDIR_QOS_SCRIPTS)/ + $(IPKG_BUILD) $(IDIR_QOS_SCRIPTS) $(PACKAGE_DIR) + diff --git a/openwrt/package/qos-scripts/files/etc/config/qos b/openwrt/package/qos-scripts/files/etc/config/qos new file mode 100644 index 0000000000..1bf991766c --- /dev/null +++ b/openwrt/package/qos-scripts/files/etc/config/qos @@ -0,0 +1,94 @@ +# QoS configuration for OpenWrt + +# INTERFACES: +config interface wan + option classgroup "Default" + option enabled 1 + option upload 128 + option download 1024 + +# RULES: +config classify + option target "Bulk" + option ipp2p "all" +config classify + option target "Bulk" + option layer7 "edonkey" +config classify + option target "Bulk" + option layer7 "bittorrent" +config classify + option target "Priority" + option ports "22,53" +config classify + option target "Normal" + option proto "tcp" + option ports "20,21,25,80,110,443,993,995" +config classify + option target "Express" + option ports "5190" +config default + option target "Express" + option proto "udp" + option pktsize "-500" +config reclassify + option target "Priority" + option proto "icmp" +config default + option target "Bulk" + option portrange "1024-65535" +config reclassify + option target "Priority" + option proto "tcp" + option pktsize "-128" + option mark "!Bulk" + option tcpflags "SYN" +config reclassify + option target "Priority" + option proto "tcp" + option pktsize "-128" + option mark "!Bulk" + option tcpflags "ACK" + + +# Don't change the stuff below unless you +# really know what it means :) + +config classgroup "Default" + option classes "Priority Express Normal Bulk" + option default "Normal" + + +config class "Priority" + option packetsize 300 + option packetdelay 10 + option maxsize 400 + option avgrate 40 + option linksharing 75 +config class "Priority_down" + option packetsize 1500 + option avgrate 20 + + +config class "Express" + option packetsize 1300 + option packetdelay 15 + option maxsize 800 + option avgrate 30 + option linksharing 80 + + +config class "Normal" + option packetsize 1500 + option packetdelay 150 + option avgrate 20 + option linksharing 30 +config class "Normal_down" + option avgrate 30 + + +config class "Bulk" + option linksharing 10 +config class "Bulk_down" + option avgrate 15 + option limitrate 85 diff --git a/openwrt/package/qos-scripts/files/etc/hotplug.d/iface/10-qos b/openwrt/package/qos-scripts/files/etc/hotplug.d/iface/10-qos new file mode 100755 index 0000000000..0682db145c --- /dev/null +++ b/openwrt/package/qos-scripts/files/etc/hotplug.d/iface/10-qos @@ -0,0 +1,2 @@ +#!/bin/sh +[ "$ACTION" = ifup ] && /usr/lib/qos.sh interface "$INTERFACE" | sh diff --git a/openwrt/package/qos-scripts/files/etc/init.d/S50qos b/openwrt/package/qos-scripts/files/etc/init.d/S50qos new file mode 100755 index 0000000000..0762a7ceb0 --- /dev/null +++ b/openwrt/package/qos-scripts/files/etc/init.d/S50qos @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/lib/qos.sh firewall | sh diff --git a/openwrt/package/qos-scripts/files/usr/bin/qos-start b/openwrt/package/qos-scripts/files/usr/bin/qos-start new file mode 100755 index 0000000000..347ca46b90 --- /dev/null +++ b/openwrt/package/qos-scripts/files/usr/bin/qos-start @@ -0,0 +1,4 @@ +#!/bin/sh +qos-stop +/usr/lib/qos.sh all | sh + diff --git a/openwrt/package/qos-scripts/files/usr/bin/qos-stat b/openwrt/package/qos-scripts/files/usr/bin/qos-stat new file mode 100755 index 0000000000..fc940a8218 --- /dev/null +++ b/openwrt/package/qos-scripts/files/usr/bin/qos-stat @@ -0,0 +1,16 @@ +#!/bin/sh +echo '#################' +echo '# EGRESS STATUS #' +echo '#################' +echo +for iface in $(tc qdisc show | grep hfsc | awk '{print $5}' | grep -v imq); do + tc -s class show dev "$iface" +done + +echo '##################' +echo '# INGRESS STATUS #' +echo '##################' +echo +for iface in $(tc qdisc show | grep hfsc | awk '{print $5}' | grep imq); do + tc -s class show dev "$iface" +done diff --git a/openwrt/package/qos-scripts/files/usr/bin/qos-stop b/openwrt/package/qos-scripts/files/usr/bin/qos-stop new file mode 100755 index 0000000000..2275ea12dc --- /dev/null +++ b/openwrt/package/qos-scripts/files/usr/bin/qos-stop @@ -0,0 +1,6 @@ +#!/bin/sh +for iface in $(tc qdisc show | grep hfsc | awk '{print $5}'); do + tc qdisc del dev "$iface" root +done +iptables -t mangle -F +iptables -t mangle -X diff --git a/openwrt/package/qos-scripts/files/usr/lib/config.sh b/openwrt/package/qos-scripts/files/usr/lib/config.sh new file mode 100644 index 0000000000..8228f5373d --- /dev/null +++ b/openwrt/package/qos-scripts/files/usr/lib/config.sh @@ -0,0 +1,52 @@ +CONFIG_PATH=${ROOT}/etc/config +_C=0 + +config_cb() { + return 0 +} +option_cb() { + return 0 +} + +config () { + config_cb "$@" + _C=$(($_C + 1)) + export CONFIG_SECTION="${2:-cfg${_C}}" + export CONFIG_${CONFIG_SECTION}_TYPE="$1" +} + +option () { + local varname="$1" ; shift + export CONFIG_${CONFIG_SECTION}_${varname}="$*" + option_cb "$varname" "$*" +} + +config_clear() { + [ -z "$CONFIG_SECTION" ] && return + for oldsetting in `set | grep ^CONFIG_${CONFIG_SECTION}_ | \ + sed -e 's/\(.*\)=.*$/\1/'` ; do + unset $oldsetting + done + unset CONFIG_SECTION +} + +config_load() { + local CD="" + if [ \! -e "$1" -a -e "$CONFIG_PATH/$1" ]; then + cd $CONFIG_PATH && local CD=1 + fi + [ -e "$1" ] && . $1 + ${CD:+cd - >/dev/null} + ${CONFIG_SECTION:+config_cb} +} + +config_get() { + case "$3" in + "") eval "echo \${CONFIG_${1}_${2}}";; + *) eval "$1=\"\${CONFIG_${2}_${3}}\"";; + esac +} + +config_set() { + export CONFIG_${1}_${2}="${3}" +} diff --git a/openwrt/package/qos-scripts/files/usr/lib/qos.sh b/openwrt/package/qos-scripts/files/usr/lib/qos.sh new file mode 100755 index 0000000000..83e6739853 --- /dev/null +++ b/openwrt/package/qos-scripts/files/usr/lib/qos.sh @@ -0,0 +1,489 @@ +#!/bin/sh +. /etc/functions.sh + +insmod="insmod" +[ -f /sbin/modprobe ] && insmod="modprobe" + +add_insmod() { + eval "export isset=\${insmod_$1}" + case "$isset" in + 1) ;; + *) append INSMOD "$insmod $* >&- 2>&-" "$N"; export insmod_$1=1;; + esac +} + +parse_matching_rule() { + local var="$1" + local section="$2" + local options="$3" + local prefix="$4" + local suffix="$5" + local proto="$6" + local mport="" + local ports="" + + append "$var" "$prefix" "$N" + for option in $options; do + case "$option" in + proto) config_get value "$section" proto; proto="${proto:-$value}";; + esac + done + config_get type "$section" TYPE + case "$type" in + classify) unset pkt; append "$var" "-m mark --mark 0";; + default) pkt=1; append "$var" "-m mark --mark 0";; + reclassify) pkt=1;; + esac + append "$var" "${proto:+-p $proto}" + for option in $options; do + config_get value "$section" "$option" + + case "$pkt:$option" in + *:srchost) + append "$var" "-s $value" + ;; + *:dsthost) + append "$var" "-d $value" + ;; + *:ipp2p) + add_insmod ipt_ipp2p + append "$var" "-m ipp2p" + case "$value" in + all) append "$var" "--edk --dc --kazaa --gnu --bit";; + *) append "$var" "--$value";; + esac + ;; + *:layer7) + add_insmod ipt_layer7 + append "$var" "-m layer7 --l7proto $value${pkt:+ --l7pkt}" + ;; + *:ports|*:srcports|*:dstports) + value="$(echo "$value" | sed -e 's,-,:,g')" + lproto=${lproto:-tcp} + case "$proto" in + ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} -m multiport";; + *) unset "$var"; return 0;; + esac + case "$option" in + ports) + config_set "$section" srcports "" + config_set "$section" dstports "" + config_set "$section" portrange "" + append "$var" "--ports $value" + ;; + srcports) + config_set "$section" ports "" + config_set "$section" dstports "" + config_set "$section" portrange "" + append "$var" "--sports $value" + ;; + dstports) + config_set "$section" ports "" + config_set "$section" srcports "" + config_set "$section" portrange "" + append "$var" "--dports $value" + ;; + esac + ports=1 + ;; + *:portrange) + config_set "$section" ports "" + config_set "$section" srcports "" + config_set "$section" dstports "" + value="$(echo "$value" | sed -e 's,-,:,g')" + case "$proto" in + ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";; + *) unset "$var"; return 0;; + esac + ports=1 + ;; + 1:pktsize) + value="$(echo "$value" | sed -e 's,-,:,g')" + add_insmod ipt_length + append "$var" "-m length --length $value" + ;; + 1:limit) + add_insmod ipt_limit + append "$var" "-m limit --limit $value" + ;; + 1:tcpflags) + case "$proto" in + tcp) append "$var" "-m tcp --tcp-flags ALL $value";; + *) unset $var; return 0;; + esac + ;; + 1:mark) + config_get class "${value##!}" classnr + [ -z "$class" ] && continue; + case "$value" in + !*) append "$var" "-m mark ! --mark $class";; + *) append "$var" "-m mark --mark $class";; + esac + esac + done + append "$var" "$suffix" + case "$ports:$proto" in + 1:) parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";; + esac +} + +config_cb() { + option_cb() { + return 0 + } + + # Section start + case "$1" in + interface) + config_set "$1" "classgroup" "Default" + config_set "$1" "upload" "128" + config_set "$1" "download" "1024" + ;; + classify|default|reclassify) + option_cb() { + append options "$1" + } + ;; + esac + + # Section end + config_get TYPE "$CONFIG_SECTION" TYPE + case "$TYPE" in + interface) + config_get enabled "$CONFIG_SECTION" enabled + config_get download "$CONFIG_SECTION" download + config_get classgroup "$CONFIG_SECTION" classgroup + config_set "$CONFIG_SECTION" imqdev "$C" + [ -z "$enabled" -o "$(($enabled))" -eq 0 ] || { + C=$(($C+1)) + INTERFACES="$INTERFACES $CONFIG_SECTION" + config_set "$classgroup" enabled 1 + } + config_get device "$CONFIG_SECTION" device + [ -z "$device" ] && device="$(nvram get ${CONFIG_SECTION}_ifname)" + config_set "$CONFIG_SECTION" device "${device:-eth0}" + ;; + classgroup) append CG "$CONFIG_SECTION";; + classify|default|reclassify) + case "$TYPE" in + classify) var="ctrules";; + *) var="rules";; + esac + config_get target "$CONFIG_SECTION" target + config_set "$CONFIG_SECTION" options "$options" + append "$var" "$CONFIG_SECTION" + unset options + ;; + esac +} + +class_main_qdisc() { + local device="$1" + awk -f - < 0)) { + dmax = 500 + umax = 1500 + m2 = 10 + rt = 0 + } else { + rt = 1 + } + + cdata = "" + pdmax = int (dmax + (umax * 8 / limit)) + if (rt == 1) { + if (share > 0) cdata = " rt" + else cdata = " ls" + if ((umax > 0) && (dmax > 0)) { + cdata = cdata " umax " umax "b dmax " pdmax "ms" + } + cdata = cdata " rate " m2 "kbit" + } + if (share > 0) { + if ((m2 > 0) && (umax > 0) && (dmax > 0)) { + cdata = cdata " ls umax " umax "b dmax " pdmax "ms rate " share "kbit" + } else { + cdata = cdata " ls m1 " share "kbit d 500ms m2 " share "kbit" + } + } + + print "tc class add dev $device parent 1:1 classid 1:${classnr}0 hfsc" cdata " ul rate " limit "kbit" +} +EOF +} + +class_leaf_qdisc() { + local device="$1" + awk -f - < 0) && (umax > 0)) qb -= int((1500 - umax) * qlen_pkt) + qb *= 8 + + # rate in bits/s + qr = rate + qr -= int((rate - m2) * qlen_avgr) + qr *= 1024 + + # queue time + qt = qlen_base + qlen_dmax * (dmax / 1000) + + # queue length + ql = int(qr * qt / qb) + if (ql < qlen_min) ql = qlen_min + + return ql +} + +BEGIN { + sfq_dthresh = 25 # use sfq for download if pktdelay set to this or lower + + limit = int("$maxrate") + m2 = int("$m2") + dmax = int("$dmax") + umax = int("$umax") + + if (!(m2 > 0)) { + dmax = 500 + umax = 1500 + m2 = 10 + } + + cqlen = ${dl_mode:+2 * }qlen(limit, m2, umax, dmax) + + printf "tc qdisc add dev $device parent 1:${classnr}0 handle ${classnr}00: " + if (("$dir" != "down") || ((dmax > 0) && (dmax <= sfq_dthresh))) { + print "sfq perturb 10 limit " cqlen + } else { + avpkt = 1200 + min = int(limit * 1024 / 8 * 0.1) + dqb = cqlen * 1500 + max = int(min + (dqb - min) * 0.25) + burst = int((2 * min + max) / (3 * avpkt)) + + print "red min " min " max " max " burst " burst " avpkt " avpkt " limit " dqb " probability 0.04 ecn" + } +} +EOF +} + +enum_classes() { + local c="0" + config_get classes "$1" classes + config_get default "$1" default + for class in $classes; do + c="$(($c + 1))" + config_set "${class}" classnr $c + case "$class" in + $default) class_default=$c;; + esac + done + class_default="${class_default:-$c}" +} + +cls_var() { + local varname="$1" + local class="$2" + local name="$3" + local type="$4" + local default="$5" + local tmp tmp1 tmp2 + config_get tmp1 "$class" "$name" + config_get tmp2 "${class}_${type}" "$name" + tmp="${tmp2:-$tmp1}" + tmp="${tmp:-$tmp2}" + export ${varname}="${tmp:-$default}" +} + +start_interface() { + local iface="$1" + local num_imq="$2" + config_get device "$iface" device + config_get enabled "$iface" enabled + [ -z "$device" -o -z "$enabled" ] && exit + config_get upload "$iface" upload + config_get halfduplex "$iface" halfduplex + config_get download "$iface" download + config_get classgroup "$iface" classgroup + + download="${download:-${halfduplex:+$upload}}" + enum_classes "$classgroup" + for dir in up${halfduplex} ${download:+down}; do + case "$dir" in + up) + upload=$(($upload * 98 / 100 - 10)) + dev="$device" + rate="$upload" + dl_mode="" + prefix="cls" + ;; + down) + add_insmod imq numdevs="$num_imq" + config_get imqdev "$iface" imqdev + download=$(($download * 96 / 100 - 64)) + dev="imq$imqdev" + rate="$download" + dl_mode=1 + prefix="d_cls" + ;; + *) continue;; + esac + for class in $classes; do + cls_var umax "$class" packetsize $dir 1500 + cls_var dmax "$class" packetdelay $dir 500 + + cls_var maxrate "$class" limitrate $dir 100 + cls_var share "$class" linksharing $dir 0 + cls_var m2 "$class" avgrate $dir 0 + maxrate=$(($maxrate * $rate / 100)) + share=$(($share * $rate / 100)) + m2=$(($m2 * $rate / 100)) + + config_get classnr "$class" classnr + append ${prefix}q "$(class_main_qdisc "$dev" "$iface")" "$N" + append ${prefix}l "$(class_leaf_qdisc "$dev" "$iface")" "$N" + append ${prefix}f "tc filter add dev $dev parent 1: prio $classnr protocol ip handle $classnr fw flowid 1:${classnr}0" "$N" + done + export dev_${dir}="ifconfig $dev up txqueuelen 5 >&- 2>&- +tc qdisc del dev $dev root >&- 2>&- +tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0 +tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit" + done + add_insmod cls_fw + add_insmod sch_hfsc + add_insmod sch_sfq + add_insmod sch_red + cat <&- 2>&- +iptables -t mangle -N ${cg}_ct >&- 2>&- +${iptrules:+${iptrules}${N}iptables -t mangle -A ${cg}_ct -j CONNMARK --save-mark} +iptables -t mangle -A ${cg} -j CONNMARK --restore-mark +iptables -t mangle -A ${cg} -m mark --mark 0 -j ${cg}_ct +$pktrules +$up$N${down:+${down}$N} +EOF + unset INSMOD +} + +start_firewall() { + add_insmod ipt_multiport + add_insmod ipt_CONNMARK + cat < +Section: net +Depends: tc, kmod-sched, iptables-mod-filter, iptables-mod-ipopt, iptables-mod-extra, iptables-mod-conntrack, iptables-mod-imq +Priority: normal +Description: QoS scripts for OpenWrt