#!/bin/sh PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH DEV=eth0 IMQ=imq0 if [ $# != 2 ]; then exit 1; fi DOWNSTREAM=221 UPSTREAM=160 DOWNSTREAM_SCALED=$[$DOWNSTREAM * $1 / 1000] UPSTREAM_SCALED=$[$UPSTREAM * $2 / 1000] tcf () { if ! tc "$@" ; then echo Failed on: tc "$@" exit 1 fi } icmp_match=" match ip protocol 1 0xff" tcp_match=" match ip protocol 6 0xff" udp_match=" match ip protocol 17 0xff" # ff == first fragment == fragment offset=0 ipff_match=" match u16 0 0x1fff at 6" icmpff_match=" $icmp_match $ipff_match" tcpff_match=" $tcp_match $ipff_match" udpff_match=" $udp_match $ipff_match" ssh_smatch=" $tcpff_match match ip sport 22 0xffff" ssh_dmatch=" $tcpff_match match ip dport 22 0xffff" telnet_smatch=" $tcpff_match match ip sport 23 0xffff" telnet_dmatch=" $tcpff_match match ip dport 23 0xffff" irc_smatch=" $tcpff_match match ip sport 6667 0xfff8" irc_dmatch=" $tcpff_match match ip dport 6667 0xfff8" ftpa_smatch=" $tcpff_match match ip sport 20 0xffff" ftpa_dmatch=" $tcpff_match match ip dport 20 0xffff" ftpp_smatch=" $tcpff_match match ip sport 21 0xffff" ftpp_dmatch=" $tcpff_match match ip dport 21 0xffff" www_smatch=" $tcpff_match match ip sport 80 0xffff" www_dmatch=" $tcpff_match match ip dport 80 0xffff" dch_smatch=" $tcpff_match match ip sport 411 0xffff" dch_dmatch=" $tcpff_match match ip dport 411 0xffff" dcho_smatch=" $tcpff_match match ip sport 4766 0xffff" dcho_dmatch=" $tcpff_match match ip dport 4766 0xffff" dcc1_smatch=" $tcpff_match match ip sport 412 0xffff" dcc1_dmatch=" $tcpff_match match ip dport 412 0xffff" dcc2_smatch=" $tcpff_match match ip sport 1412 0xffff" dcc2_dmatch=" $tcpff_match match ip dport 1412 0xffff" #tmp_smatch=" $tcpff_match match ip sport 8002 0xffff" #tmp_dmatch=" $tcpff_match match ip dport 8002 0xffff" ut_smatch=" $udpff_match match ip sport 7777 0xff00" ut_dmatch=" $udpff_match match ip dport 7777 0xfc00" ihl20_match=" match u8 0x05 0x0f at 0" lt64_match=" match u16 0x0000 0xffc0 at 2" tcpackbit_match="match u8 0x10 0xff at 33" tcpsynbit_match="match u8 0x02 0x0f at 33" tos_maxspeed=" match ip tos 0x08 0xf8" tos_mindelay=" match ip tos 0x10 0xf8" tcpack_match=" $tcpff_match $ihl20_match $lt64_match $tcpackbit_match" tcpsyn_match=" $tcpff_match $lt64_match $tcpsynbit_match" #any_match=" match u8 0 0 at 0" ################################################################################################ ###### #### ##### ###### #### #### # # # # # # # # ##### # # # ##### #### #### # # ### ##### # # # # # # # # # # # # # ###### #### # # ###### #### #### ut_min_kbit=60 ut_max_kbit=$UPSTREAM udp_min_kbit=40 udp_max_kbit=$[$UPSTREAM*80/100] ssh_min_kbit=50 ssh_max_kbit=150 ack_min_kbit=$[$UPSTREAM*20/100] ack_max_kbit=$[$UPSTREAM*30/100] rest_min_kbit=$[$UPSTREAM-$ut_min_kbit-$udp_min_kbit-$ssh_min_kbit] rest_max_kbit=$UPSTREAM_SCALED rest_div_kbit=$[$rest_max_kbit-$ack_min_kbit] burst=$[$UPSTREAM*1024/790] echo "----------------------------" echo "up $UPSTREAM_SCALED / $UPSTREAM" echo "burst $burst" echo "" echo "ut_min $ut_min_kbit" echo "ut_max $ut_max_kbit" echo "" echo "udp_min $udp_min_kbit" echo "udp_max $udp_max_kbit" echo "" echo "ssh_min $ssh_min_kbit" echo "ssh_max $ssh_max_kbit" echo "" echo "ack_min $ack_min_kbit" echo "ack_max $ack_max_kbit" echo "" echo "rest_min $rest_min_kbit" echo "rest_max $rest_max_kbit" echo "rest_div $rest_div_kbit" tc qdisc del dev $DEV root 2> /dev/null > /dev/null tc qdisc del dev $DEV ingress 2> /dev/null > /dev/null tcf qdisc add dev $DEV root handle 200: htb default 99 r2q 100 tcf class add dev $DEV parent 200:0 classid 200:1 htb burst $burst rate ${UPSTREAM}kbit cburst 1400 tcf class add dev $DEV parent 200:1 classid 200:50 htb burst $burst rate ${ut_min_kbit}kbit cburst 80 ceil ${ut_max_kbit}kbit prio 0 tcf class add dev $DEV parent 200:1 classid 200:60 htb burst $burst rate ${udp_min_kbit}kbit cburst 80 ceil ${udp_max_kbit}kbit prio 1 tcf class add dev $DEV parent 200:1 classid 200:20 htb burst $burst rate ${ssh_min_kbit}kbit cburst 140 ceil ${ssh_max_kbit}kbit prio 1 tcf class add dev $DEV parent 200:1 classid 200:2 htb burst $burst rate ${rest_min_kbit}kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 2 tcf class add dev $DEV parent 200:2 classid 200:10 htb burst $burst rate ${ack_min_kbit}kbit cburst 80 ceil ${ack_max_kbit}kbit prio 2 tcf class add dev $DEV parent 200:2 classid 200:30 htb burst $burst rate $[$rest_div_kbit*20/(20+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 #tcf class add dev $DEV parent 200:2 classid 200:40 htb burst $burst rate $[$rest_div_kbit* 1/(20+1+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 tcf class add dev $DEV parent 200:2 classid 200:99 htb burst $burst rate $[$rest_div_kbit*20/(20+20)]kbit cburst 1000 ceil ${rest_max_kbit}kbit prio 3 tcf qdisc add dev $DEV parent 200:50 handle 250: bfifo limit 2000 tcf qdisc add dev $DEV parent 200:60 handle 260: bfifo limit 2000 tcf qdisc add dev $DEV parent 200:20 handle 220: sfq perturb 10 tcf qdisc add dev $DEV parent 200:10 handle 210: sfq perturb 10 tcf qdisc add dev $DEV parent 200:30 handle 230: sfq perturb 10 #tcf qdisc add dev $DEV parent 200:40 handle 240: sfq perturb 20 tcf qdisc add dev $DEV parent 200:99 handle 299: sfq perturb 10 # in my empirical tests I found that ssh consumes upstream at most 6kB/s, which is ~50kbit # filters # 250 for ut # 260 for other udp traffic # 220 for ssh & telnet & irc [max 50kbit/s] # 210 for tcp syns [max 3/sec], acks & icmp # 230 for www & ftp ## 240 for dc # 299 for rest ######################################################################## # for egress: # s == server, d == client tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ut_dmatch flowid 200:50 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ut_smatch flowid 200:50 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $udp_match flowid 200:60 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ssh_smatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ssh_dmatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $telnet_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $telnet_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $irc_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $irc_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $icmp_match flowid 200:10 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $tcpack_match flowid 200:10 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $tcpsyn_match police rate 1kbit burst 40 mtu 9k continue flowid 200:10 # this rule matches only 3 syns/sec tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $www_smatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $www_dmatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ftpa_smatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ftpa_dmatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ftpp_smatch flowid 200:30 tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $ftpp_dmatch flowid 200:30 #tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dch_dmatch flowid 200:40 #tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcho_dmatch flowid 200:40 #tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcc1_dmatch flowid 200:40 #tcf filter add dev $DEV parent 200: protocol ip prio 1 u32 $dcc2_dmatch flowid 200:40 ################################################################################################ # # # #### ##### ###### #### #### # ## # # # # # # # # # # # # # # # ##### #### #### # # # # # ### ##### # # # # # ## # # # # # # # # # # # # #### # # ###### #### #### # golden bitrate multiplier: 7.98722044728434504792 ut_min_kbit=60 ut_max_kbit=$DOWNSTREAM udp_min_kbit=40 udp_max_kbit=$[$DOWNSTREAM*80/100] ssh_min_kbit=50 ssh_max_kbit=150 ack_min_kbit=$[$DOWNSTREAM*20/100] ack_max_kbit=$[$DOWNSTREAM*30/100] rest_min_kbit=$[$DOWNSTREAM-$ut_min_kbit-$udp_min_kbit-$ssh_min_kbit] rest_max_kbit=$DOWNSTREAM_SCALED rest_div_kbit=$[$rest_max_kbit-$ack_min_kbit] burst=$[$DOWNSTREAM*1024/790] echo "----------------------------" echo "down $DOWNSTREAM_SCALED / $DOWNSTREAM" echo "burst $burst" echo "" echo "ut_min $ut_min_kbit" echo "ut_max $ut_max_kbit" echo "" echo "udp_min $udp_min_kbit" echo "udp_max $udp_max_kbit" echo "" echo "ssh_min $ssh_min_kbit" echo "ssh_max $ssh_max_kbit" echo "" echo "ack_min $ack_min_kbit" echo "ack_max $ack_max_kbit" echo "" echo "rest_min $rest_min_kbit" echo "rest_max $rest_max_kbit" echo "rest_div $rest_div_kbit" modprobe imq ip link set $IMQ up tc qdisc del dev $IMQ root 2> /dev/null > /dev/null tcf qdisc add dev $IMQ root handle 200: htb default 99 r2q 100 tcf class add dev $IMQ parent 200:0 classid 200:1 htb burst $burst rate ${DOWNSTREAM}kbit cburst 1400 tcf class add dev $IMQ parent 200:1 classid 200:50 htb burst $burst rate ${ut_min_kbit}kbit cburst 80 ceil ${ut_max_kbit}kbit prio 0 tcf class add dev $IMQ parent 200:1 classid 200:60 htb burst $burst rate ${udp_min_kbit}kbit cburst 80 ceil ${udp_max_kbit}kbit prio 1 tcf class add dev $IMQ parent 200:1 classid 200:20 htb burst $burst rate ${ssh_min_kbit}kbit cburst 140 ceil ${ssh_max_kbit}kbit prio 1 tcf class add dev $IMQ parent 200:1 classid 200:2 htb burst $burst rate ${rest_min_kbit}kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 2 tcf class add dev $IMQ parent 200:2 classid 200:10 htb burst $burst rate ${ack_min_kbit}kbit cburst 80 ceil ${ack_max_kbit}kbit prio 2 tcf class add dev $IMQ parent 200:2 classid 200:30 htb burst $burst rate $[$rest_div_kbit*20/(20+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 #tcf class add dev $IMQ parent 200:2 classid 200:40 htb burst $burst rate $[$rest_div_kbit* 1/(20+1+20)]kbit cburst 1500 ceil ${rest_max_kbit}kbit prio 3 tcf class add dev $IMQ parent 200:2 classid 200:99 htb burst $burst rate $[$rest_div_kbit*20/(20+20)]kbit cburst 1000 ceil ${rest_max_kbit}kbit prio 3 tcf qdisc add dev $IMQ parent 200:50 handle 250: bfifo limit 2000 tcf qdisc add dev $IMQ parent 200:60 handle 260: bfifo limit 2000 tcf qdisc add dev $IMQ parent 200:20 handle 220: sfq perturb 10 tcf qdisc add dev $IMQ parent 200:10 handle 210: sfq perturb 10 tcf qdisc add dev $IMQ parent 200:30 handle 230: sfq perturb 10 #tcf qdisc add dev $DEV parent 200:40 handle 240: sfq perturb 20 tcf qdisc add dev $IMQ parent 200:99 handle 299: sfq perturb 10 # filters # 250 for ut # 260 for other udp traffic # 220 for ssh & telnet & irc [max 50kbit/s] # 210 for tcp syns [max 3/sec], acks & icmp # 230 for www & ftp ## 240 for dc # 299 for rest ######################################################################## # for ingress: # d == server, s == client tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ut_dmatch flowid 200:50 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ut_smatch flowid 200:50 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $udp_match flowid 200:60 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ssh_smatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ssh_dmatch $tos_mindelay police rate 50kbit burst 16k continue flowid 200:20 # max prioritized ssh traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $telnet_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $telnet_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized telnet traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $irc_smatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $irc_dmatch police rate 50kbit burst 16k continue flowid 200:20 # max prioritized irc traffic 50kb/s tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $icmp_match flowid 200:10 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $tcpack_match flowid 200:10 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $tcpsyn_match police rate 1kbit burst 40 mtu 9k continue flowid 200:10 # this rule matches only 3 syns/sec tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $www_smatch flowid 200:30 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $www_dmatch flowid 200:30 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ftpa_smatch flowid 200:30 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ftpa_dmatch flowid 200:30 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ftpp_smatch flowid 200:30 tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $ftpp_dmatch flowid 200:30 #tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $dch_dmatch flowid 200:40 #tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $dcho_dmatch flowid 200:40 #tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $dcc1_dmatch flowid 200:40 #tcf filter add dev $IMQ parent 200: protocol ip prio 1 u32 $dcc2_dmatch flowid 200:40