# yet another post about traffic shaping...

## makism

hello, in the past few days i`m trying to setup some kind of traffic shaping - bandwidth limiter.

i`ve read and tried many `recipes` about tc/iptables/qos/tos/imq/sfq/etc :S and stuff but i seem to miss the point...

my adsl connection is 2mbs/256kbs. my pc is connected to the adsl router.

i want to just use the half speeds, 1mb/128kbs.

i`m currently using the script provided from asdf, but i figured out that after a while it does not work so well... :S

```

#!/sbin/runscript

IFACE=eth1

# Priority marks

MARKPRIO1="1"

MARKPRIO2="2"

MARKPRIO3="3"

# Rates

UPRATE="20kbit"

PRIORATE1="50kbit"

PRIORATE2="30kbit"

PRIORATE3="10kbit"

# Quantum

QUANTUM1="12187"

QUANTUM2="8625"

QUANTUM3="5062"

# Burst

BURST1="4k"

BURST2="2k"

BURST3="1k"

CBURST1="3k"

CBURST2="2k"

CBURST3="1k"

depend() {

   after net.eth1

}

start() {

   ebegin "Starting traffinc shaping"

   # Set queue length for IFACE

   ifconfig $IFACE txqueuelen 16

   # Specify queue discipline

   tc qdisc add dev $IFACE root handle 1:0 htb default 103 r2q 1

   # Set root class

   tc class add dev $IFACE parent 1:0 classid 1:1 htb rate $UPRATE burst $BURST1 cburst $CBURST1

   # Specify sub classes

   tc class add dev $IFACE parent 1:1 classid 1:101 htb rate $PRIORATE1 ceil $UPRATE quantum $QUANTUM1 burst $BURST1 cburst $CBURST1 prio 0

   #tc class add dev $IFACE parent 1:1 classid 1:102 htb rate $PRIORATE2 ceil $UPRATE quantum $QUANTUM2 burst $BURST2 cburst $CBURST2 prio 1

   #tc class add dev $IFACE parent 1:1 classid 1:103 htb rate $PRIORATE3 ceil $UPRATE quantum $QUANTUM3 burst $BURST3 cburst $CBURST3 prio 2

   # Filter packets

   tc filter add dev $IFACE parent 1:0 protocol ip prio 0 handle $MARKPRIO1 fw classid 1:101

   #tc filter add dev $IFACE parent 1:0 protocol ip prio 1 handle $MARKPRIO2 fw classid 1:102

   #tc filter add dev $IFACE parent 1:0 protocol ip prio 2 handle $MARKPRIO3 fw classid 1:103

   # Add queuing disciplines

   tc qdisc add dev $IFACE parent 1:101 sfq perturb 16 quantum $QUANTUM1

   #tc qdisc add dev $IFACE parent 1:102 sfq perturb 16 quantum $QUANTUM2

   #tc qdisc add dev $IFACE parent 1:103 sfq perturb 16 quantum $QUANTUM3

}

stop() {

   ebegin "Stopping traffic shaping"

   tc qdisc del dev $IFACE root

}

```

i`m really sick and tired of tc :p, so if anyone would just help me out i would reaaallyy appreciate it =).

thanks. byebye.

----------

## alex.blackbit

AFAIK shorewall is a nice and easy to configure frontend to both netfilter and tc.

----------

## jomen

...maybe this can be of help to you as an example...

I tried to comment as much as possible.

...I never used "quantum" though...

This script I use currently on an router running OpenWRT and am quite happy with the results.

I still can use my own uplink almost without noticing the fact that there are others using it quite heavily too at the same time.

The background:

I'm participating on a mesh-network - and providing my internet uplink to the project.

See

http://global.freifunk.net/

http://leipzig.freifunk.net/

for some info.

The whole project here in my home town has 600+ mesh-nodes - each of which could have an unknown number of LAN/WLAN-clients and could possibly use my uplink...

Usually only 10 to 20 nodes (with a still unknown number of LAN/WLAN-clients are routed through my uplink at a time because I'm not the only uplink - of course.

To get good performance P2P-traffic has to be limited and the available bandwith used as efficiently as possible.

shorewall, ipcop and such are ruled out since the shaping has to be done on the router itself - a Home-Router running a variant of OpenWRT and meshing software (olsrd). 

My shot on meeting these requirements is the script below:

```
#!/bin/sh

# Interface on which the traffic should be shaped

# NETDEVICE=$(nvram get wan_device)

NETDEVICE=ppp0

case $1 in

   start)

test -n "$FAILSAFE" && exit

# load neccesary modules

# !!! no output will be generated in case of failure !!!

# make sure the modules are available

# todo (if needed):  write a test if modules are successfully loaded

# the functionality of these 3 is needed - but these are compiled into kernel - no loading neccesary

# but this may change...

# insmod sch_prio

# insmod sch_sfq

# insmod cls_u32

insmod cls_fw > /dev/null 2>&1

insmod ipt_CONNMARK > /dev/null 2>&1

insmod ipt_connmark > /dev/null 2>&1

insmod ipt_conntrack > /dev/null 2>&1

insmod ipt_layer7 > /dev/null 2>&1

insmod ipt_length > /dev/null 2>&1

insmod ipt_tos > /dev/null 2>&1

insmod sch_htb > /dev/null 2>&1

# insmod sch_ingress > /dev/null 2>&1

# UPRATE is (with DSL) about 1/10 of the given Bandwith (1 Mbit == 1024 KBit --> 1/10 davon is about 128 KBit)

# this script is tailored for a 2 MBit DSL

# do set the rate at a little less than full bandwith to make sure the modems send-queue does never get filled

# as this would lead to throwing away packets and the need to resend them

# to avoid this under any circumstance is exactly what is needed/wanted here

#

# Downrate is the rated speed of the DSL - or here: the speed the incoming packets is to be throtteled down to...

#

# this is commented out now as it is not useful - you have NO control whatsoever over the speed/rate of incoming packets

# they are just the unknown answer to what was requested 

# P2PRATE is the max bandwith _ever_ to be given to filesharing 

# it could be any high rate - but the purpose of this script is to limit their impact on the overall performance as good as possile

# P2P is exactly NOT a priority here - to the contrary

# 

# with the standard filter settings - less than 12kBit is _not_ possible - for NO queue here

# I did not bother to figure out how to make this even less

# the filters algorithm may not catch all packets belonging to P2P - so the actual rate may be a little higher in reality

# PRIORATE_x is the base bandwith for each and every of the prio-classes,

# they can "borrow" bandwith from others if it is available and not actually used

# PRIORATE1 --> interactive class - small packets, TOS minimize delay (ACK - but only small ACK's...p2p does also use large ACK's for data-transfer...)

# PRIORATE2 --> general data-traffic: large packets, TOS maximize throughput

# PRIORATE3 --> in here goes everything not explicitely marked otherwise

# P2PRATE_LOW + P2PRATE_HIGH --> a try to catch _all_ filesharing 

# these are given a low amount of bandwith to start with - and are _never_ allowed to get the full bandwith...

# see: P2PRATE

#

# Exception: P2PRATE_OWNER - the owner (me) should not be limited in any way even with filesharing

#

# UPRATE + BURST is the max. rate that is allowed to get out to the Internet - avoiding filling the modem-queue

#

# DOWNRATE + DOWNBURST is the max. for the incoming queue

# commented out as one just has no control over ingress (rate of inbound traffic)

#

# !! P2PRATE_LOW + P2PRATE_HIGH + PRIORATE1 + PRIORATE2 + PRIORATE3 = UPRATE (close enough...) !!

# defining variables

# the rates for the different priority-classes

UPRATE="250kbit"

# DOWNRATE="2mbit"

P2PRATE_LOW="12kbit"

P2PRATE_HIGH="24kbit"

PRIORATE1="24kbit"

PRIORATE2="24kbit"

PRIORATE3="24kbit"

P2PRATE_OWNER=$PRIORATE2

# Burst - for a short time the above set rates can be exceeded by this amount

BURST="24k"

# DOWNBURST="50k"

# MARKPRIO_x - the MARKs iptables will set when identifying a matching packet

# these MARKs are the basis to shape all the traffic

# 11 is used here for the highest priority

# 19 is used for the lowest priority

# the 3 groups below are MY partitioning-scheme of all traffic into priority-classes

# 11 - 13 = high  14 - 16 = normal  17 - 19 = low

MARKPRIO_1="11"

MARKPRIO_2="12"

MARKPRIO_3="13"

MARKPRIO_4="14"

MARKPRIO_5="15"

MARKPRIO_6="16"

MARKPRIO_7="17"

MARKPRIO_8="18"

MARKPRIO_9="19"

# create the chains and empty them

      iptables -t mangle -N p2pmatch

      iptables -t mangle -F p2pmatch

      iptables -t mangle -N packetsize

      iptables -t mangle -F packetsize

      iptables -t mangle -N typeofservice

      iptables -t mangle -F typeofservice

      iptables -t mangle -N split

      iptables -t mangle -F split

      iptables -t mangle -N higher_prio

      iptables -t mangle -F higher_prio

      iptables -t mangle -N lower_prio

      iptables -t mangle -F lower_prio

## the chains and what they do

# test if traffic belongs to filesharing

      iptables -t mangle -A POSTROUTING -j p2pmatch

# here is a place for clients entirely disabled to do any filesharing at all

# after the traffic has been MARKed ($MARKPRIO_6) it can be filtered based on host/source/destination address

      iptables -t mangle -A POSTROUTING -s 104.61.112.15 -m mark --mark $MARKPRIO_6 -j DROP

# a RETURN (go up one level) if packets arealready MARKed P2P

      iptables -t mangle -A POSTROUTING -m mark --mark $MARKPRIO_6 -j RETURN

# go through chains packetsize, typeofservice - if not yet MARKed...

      iptables -t mangle -A POSTROUTING -j packetsize

      iptables -t mangle -A POSTROUTING -j typeofservice

# mark packets belonging to filesharing - edonkey was the most common here

# to save computing-time I tried to arrange these matches based on how often they occured here

# reason: this script is to be run on a 200 MHz Home-Router with OpenWRT and a lot of NAT - I wanted to keep the load as low as possible

# after each check there is a RETURN target to save the (possibly) computing-intensive and useless check for the remaining P2P-protocols

      iptables -t mangle -A p2pmatch -j CONNMARK --restore-mark

      iptables -t mangle -A p2pmatch -m mark --mark $MARKPRIO_6 -j RETURN

       iptables -t mangle -A p2pmatch -m layer7 --l7proto edonkey -j MARK --set-mark $MARKPRIO_6

      iptables -t mangle -A p2pmatch -m mark --mark $MARKPRIO_6 -j RETURN

      iptables -t mangle -A p2pmatch -m layer7 --l7proto bittorrent -j MARK --set-mark $MARKPRIO_6

      iptables -t mangle -A p2pmatch -m mark --mark $MARKPRIO_6 -j RETURN

      iptables -t mangle -A p2pmatch -m layer7 --l7proto gnutella -j MARK --set-mark $MARKPRIO_6

      iptables -t mangle -A p2pmatch -j CONNMARK --save-mark

# set MARK based on packet-size, if TOS "Normal-Service"

      iptables -t mangle -A packetsize -m tos --tos ! Normal-Service -j RETURN

      iptables -t mangle -A packetsize -m length --length 0:128 -j MARK --set-mark $MARKPRIO_4

      iptables -t mangle -A packetsize -m length --length 129: -j MARK --set-mark $MARKPRIO_5

# match and set MARK based on already present TOS field

      iptables -t mangle -A typeofservice -m tos --tos Minimize-Delay -j MARK --set-mark $MARKPRIO_4

      iptables -t mangle -A typeofservice -m tos --tos Maximize-Throughput -j MARK --set-mark $MARKPRIO_5

# chain "split" to be able to assign different priorities to different clients - such as i.e.: the owner of the line...

      iptables -t mangle -A POSTROUTING -j split

# actual split for clients, which are to get higher or lower priority than the rest

# i.e. split for "higher prio" - everything on the local LAN or a whole subnet for example

      iptables -t mangle -A split -s 192.168.1.0/24 -j higher_prio

      iptables -t mangle -A split -s 104.61.114.17 -j higher_prio

# i.e. split for "lower prio" - just one client or a whole subnet

#      iptables -t mangle -A split -s 104.61.111.0/24 -j lower_prio

#      iptables -t mangle -A split -s 104.61.111.10 -j lower_prio

# chain "higher_prio" - what has been put into "higher_prio" above gets its MARK value rewritten

# MARKPRIO_4 gets MARKPRIO_1

# MARKPRIO_5 gets MARKPRIO_2

# MARKPRIO_6 gets MARKPRIO_3

      iptables -t mangle -A higher_prio -m mark --mark $MARKPRIO_4 -j MARK --set-mark $MARKPRIO_1

      iptables -t mangle -A higher_prio -m mark --mark $MARKPRIO_5 -j MARK --set-mark $MARKPRIO_2

      iptables -t mangle -A higher_prio -m mark --mark $MARKPRIO_6 -j MARK --set-mark $MARKPRIO_3

# similar thing for "lower_prio"

      iptables -t mangle -A lower_prio -m mark --mark $MARKPRIO_4 -j MARK --set-mark $MARKPRIO_7

      iptables -t mangle -A lower_prio -m mark --mark $MARKPRIO_5 -j MARK --set-mark $MARKPRIO_8

      iptables -t mangle -A lower_prio -m mark --mark $MARKPRIO_6 -j MARK --set-mark $MARKPRIO_9

# htb as traffic-handler - default for unclassified traffic (should'nt be any) is flowid 1:100 (normal priority)

# everything else is going into the assigned queues

      tc qdisc add dev $NETDEVICE root handle 1: htb default 100 r2q 1

# set root class

      tc class add dev $NETDEVICE parent 1: classid 1:1 htb rate $UPRATE burst $BURST

# the sub-classes

# into the first 3 (which are served first) go all packets with highest priority

# here goes also  P2PRATE_OWNER to NOT restrict the owner in using P2P - as all others are

      tc class add dev $NETDEVICE parent 1:1 classid 1:10 htb rate $PRIORATE1 ceil $UPRATE burst $BURST prio 1

      tc class add dev $NETDEVICE parent 1:1 classid 1:20 htb rate $PRIORATE2 ceil $UPRATE burst $BURST prio 2

      tc class add dev $NETDEVICE parent 1:1 classid 1:30 htb rate $P2PRATE_OWNER ceil $UPRATE prio 3

# the next 3 are "normal" priority

      tc class add dev $NETDEVICE parent 1:1 classid 1:40 htb rate $PRIORATE1 ceil $UPRATE burst $BURST prio 4

      tc class add dev $NETDEVICE parent 1:1 classid 1:50 htb rate $PRIORATE2 ceil $UPRATE burst $BURST prio 5

      tc class add dev $NETDEVICE parent 1:1 classid 1:60 htb rate $P2PRATE_LOW ceil $P2PRATE_HIGH prio 6

# the last 3 are for packets (clients) explicitely set to "low" priority

      tc class add dev $NETDEVICE parent 1:1 classid 1:70 htb rate $PRIORATE1 ceil $UPRATE burst $BURST prio 7

      tc class add dev $NETDEVICE parent 1:1 classid 1:80 htb rate $PRIORATE2 ceil $UPRATE burst $BURST prio 8

      tc class add dev $NETDEVICE parent 1:1 classid 1:90 htb rate $P2PRATE_LOW ceil $P2PRATE_LOW prio 9

# default-class (should anything have slipped by - it goes in here

      tc class add dev $NETDEVICE parent 1:1 classid 1:100 htb rate $PRIORATE3 ceil $UPRATE burst $BURST prio 10

# define sqf as qdisc for the sub-classes 

# high

      tc qdisc add dev $NETDEVICE parent 1:10 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:20 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:30 sfq perturb 10

# normal

      tc qdisc add dev $NETDEVICE parent 1:40 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:50 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:60 sfq perturb 10

# low

      tc qdisc add dev $NETDEVICE parent 1:70 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:80 sfq perturb 10

      tc qdisc add dev $NETDEVICE parent 1:90 sfq perturb 10

# default

      tc qdisc add dev $NETDEVICE parent 1:100 sfq perturb 10

# put MARKed packets into the sub-classes

# everything from chain "split" --> "higher_prio" goes into 1:10 / 1:20 / 1:30

# normal traffic goes into 1:40 / 1:50 / 1:60 

# everything from chain "split" --> "lower_prio" goes into 1:70 / 1:80 / 1:90

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 1 handle $MARKPRIO_1 fw flowid 1:10

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 2 handle $MARKPRIO_2 fw flowid 1:20

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 3 handle $MARKPRIO_3 fw flowid 1:30

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 4 handle $MARKPRIO_4 fw flowid 1:40

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 5 handle $MARKPRIO_5 fw flowid 1:50

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 7 handle $MARKPRIO_6 fw flowid 1:60

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 8 handle $MARKPRIO_7 fw flowid 1:70

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 9 handle $MARKPRIO_8 fw flowid 1:80

      tc filter add dev $NETDEVICE parent 1:0 protocol ip prio 10 handle $MARKPRIO_9 fw flowid 1:90

# slowdown downlink

# commented out - it was just an experiment 

#      tc qdisc add dev $NETDEVICE handle ffff: ingress

#      tc filter add dev $NETDEVICE parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate $DOWNRATE burst $DOWNBURST drop flowid :1

   ;;

   stop)

#

# the "stop" part of the script

# remove the whole setup in reverse order of creation

      tc qdisc del dev $NETDEVICE root handle 1: htb default 100

#      tc qdisc del dev $NETDEVICE handle ffff: ingress

      iptables -t mangle -D POSTROUTING -j p2pmatch

      iptables -t mangle -F p2pmatch

      iptables -t mangle -X p2pmatch

      iptables -t mangle -D POSTROUTING -j packetsize

      iptables -t mangle -F packetsize

      iptables -t mangle -X packetsize

      iptables -t mangle -D POSTROUTING -j typeofservice

      iptables -t mangle -F typeofservice

      iptables -t mangle -X typeofservice

      iptables -t mangle -D POSTROUTING -j split

      iptables -t mangle -F split

      iptables -t mangle -X split

      iptables -t mangle -F higher_prio

      iptables -t mangle -X higher_prio

      iptables -t mangle -F lower_prio

      iptables -t mangle -X lower_prio

      

      iptables -t mangle -F POSTROUTING

   ;;

   restart)

      $0 stop

      $0 start

   ;;

   *)

      echo "Usage: $0 start|stop|restart"

   ;;

esac
```

----------

## makism

i thank you both of you, i`ll check right now shorewall and the script.

thanks again =)

----------

## eulogious

Hello, I just wanted to thank you jomen for the awesome QoS script.  I was messing around with it, and kinda had it working, then I came across this, and it totally works just the way I want it too!  Granted I had to modify it for my needs, but still, thanks for the ground work man!  This is exactly why I love the gentoo forums   :Very Happy:   Thanks again jomen!

----------

