Showing posts with label bandwidth. Show all posts
Showing posts with label bandwidth. Show all posts

Thursday, September 8, 2011

Traffic Control

Introduction

Linux's traffic control functionality offers a lot of capabilities related to influencing the rate of flow, as well as latency, of primarily outgoing but also in some cases incoming network traffic. It is designed to be a "construction kit" rather than a turn-key system, where complex network traffic policing and shaping decisions can be made using a variety of algorithms. The Linux traffic control code is also often used by academia for research purposes, where is it can be a useful mechanism to simulate and explore the impact of a variety of different network behaviors. See netem for an example of a simulation framework that can be used for this purpose.
Of course, Linux traffic control can also be extremely useful in an IT context, and this document is intended to focus on the practical, useful applications of Linux traffic control, where these capabilities can be applied to solve problems that are often experienced on modern networks.

Saturday, March 26, 2011

Fair traffic shaping an ADSL line for a local network using Linux

I am currently writing this up! In the meantime, full details are located here
Traffic shaping a standard ADSL link in order to share it with a couple of hundred users is a common problem. There are dozens of bits of software and firewall scripts out there already to do this. This particular script is one that I have written. It aims to be as simple as possible, is easily customised, and uses connlimit to identify P2P users. Although the latter is not 100% reliable, it seems to work pretty well and does not fall foul of any new/changed P2P software that happens to some of the other scripts.


Contents

[hide]

[edit] Software required

Any recent Linux distribution should be able to be used for these scripts. The example shown here uses Debian.
The following packages are required:
  • Kernel 2.6.26
  • IPset
IPset is not yet in the stable kernel, so the easiest way to install it (in Debian) is:
apt-get install ipset
apt-get install module-assistant xtables-addons-source
module-assistant prepare
module-assistant auto-install xtables-addons-source
(Note: at the time of writing, the above packages are not in stable, so will have to be installed from testing repositories. See here for an example).
A better way is possibly:
apt-get install ipset
apt-get install module-assistant
apt-get install netfilter-extensions-source
module-assistant build netfilter-extensions-source
module-assistant install netfilter-extensions-source
or from recent feedback:
aptitude install ipset ipset-source module-assistant
module-assistant auto-install ipset-source
But I need to check this on a clean install.

[edit] Principle of operation

  • All traffic is given an iptables MARK depending on its type:
    • 10 for low latency traffic such as SSH shells
    • 30 for normal web browsing
    • 40 for any normal traffic including large web downloads
    • 60 for P2P traffic
  • HTB is used to create classes for all this traffic
  • All traffic shaping is hashed by client, not by connection. This means that one user with several large download connections will get the same amount of total bandwidth as one user with one connection. The default within Linux and routers is normally to do it per connection.
  • ipset is used to generate a list of client IP addresses that are using P2P software.
  • connlimit is used to detect P2P software. The firewall rules below look for multiple connections to high port numbers from a client.


[edit] Assumptions

  • ppp0 is the internet connection
  • eth0 is the local network connection


[edit] Firewall rules required

I will first describe some of the rules that form the basis of the traffic shaping. Later in this page the full script is shown.
The first task is to create an ipset for storing the IP addresses of all our naughty users slurping up the bandwidth with constantly downloading P2P software. A timeout of 60 seconds is used, so that as soon as they turn off their software their IP address is removed. The current IP addresses in the IPset can be monitored with the 'ipset -L' comand from the bash prompt
# Create a set called p2p with 60 second timeout
ipset -N p2p iptree --timeout 60
Next we need to mark traffic as required, using the principles set out earlier. The following code contains some examples.
# First mark all traffic coming in on the ppp link with the default of 40
$IPTABLES -t mangle -A PREROUTING -i ppp0 -j MARK --set-mark 40

# Mark http and https traffic as 30, both in and out
$IPTABLES -t mangle -A FORWARD -p tcp --sport 80 -i ppp0 -j MARK --set-mark 30
$IPTABLES -t mangle -A FORWARD -p tcp --dport 80 -o ppp0 -j MARK --set-mark 30
$IPTABLES -t mangle -A FORWARD -p tcp --sport 443 -i ppp0 -j MARK --set-mark 30
$IPTABLES -t mangle -A FORWARD -p tcp --dport 443 -i eth0 -j MARK --set-mark 30

# Mark in and out SSH traffic as high priority
$IPTABLES -t mangle -A FORWARD -p tcp --sport 22 -i ppp0 -j MARK --set-mark 10
$IPTABLES -t mangle -A FORWARD -p tcp --dport 22 -o ppp0 -j MARK --set-mark 10

# Mark any traffic destined for the local machine with 1
# This traffic does not need shaping and we will ignore it later
$IPTABLES -t mangle -A POSTROUTING --source 10.0.0.1 -j MARK --set-mark 1
$IPTABLES -t mangle -A POSTROUTING --destination 10.0.0.1 -j MARK --set-mark 1

# Mark any large downloads as 40 (they may have been marked 30 or 10 earlier)
$IPTABLES -t mangle -A FORWARD -m connbytes --connbytes 504857: --connbytes-dir both \
  --connbytes-mode bytes -j MARK --set-mark 40

Now we need to look out for all those P2P connections. We're going to find these out by looking for a client on the network making lots of connections to high port numbers, which is generally what P2P software does. This isn't foolproof of course: I have seen P2P software start to use port 80, and there could be false negatives, but on the whole it seems to work better than any other solutions out there that I have tried.
# TCP traffic from clients going to high port numbers
# Add the client IP address to the ipset
$IPTABLES -t mangle -A FORWARD -o ppp0 -p tcp --dport 1024: \
 -m connlimit --connlimit-above 8 -j SET --add-set p2p src 

# UDP traffic from clients going to high port numbers
$IPTABLES -t mangle -A FORWARD -o ppp0 -p udp --dport 1024: \
 -m connlimit --connlimit-above 4 -j SET --add-set p2p src 

# TCP traffic in to clients from high port numbers
$IPTABLES -t mangle -A FORWARD -i ppp0 -p tcp --sport 1024: \
 -m connlimit --connlimit-above 8 -j SET --add-set p2p dst

# UDP traffic in to clients from high port numbers
$IPTABLES -t mangle -A FORWARD -i ppp0 -p udp --sport 1024: \
 -m connlimit --connlimit-above 4 -j SET --add-set p2p dst
The above rules just add the client IP address to the ipset. We now need to mark the traffic, which the following rules do. On one network, traffic became so slow that I marked ALL traffic to and from those clients as '60'. This certainly sped the network up, but of course the entire internet connection for that client became really slow. If you want to do that just remove the destination port parameters.
# Once a user is in the p2p IPSET, these rules mark their traffic
# that is above 1024 to the lowest priority

# TCP traffic from the client
$IPTABLES -t mangle -A FORWARD -o ppp0 -p tcp --dport 1024: \
 -m set --set p2p src -j MARK --set-mark 60

# TCP traffic to the client
$IPTABLES -t mangle -A FORWARD -i ppp0 -p tcp --sport 1024: \
 -m set --set p2p dst -j MARK --set-mark 60

# UDP traffic from the client
$IPTABLES -t mangle -A FORWARD -o ppp0 -p udp --dport 1024: \
 -m set --set p2p src -j MARK --set-mark 60

# UDP traffic to the client
$IPTABLES -t mangle -A FORWARD -i ppp0 -p udp --sport 1024: \
 -m set --set p2p dst -j MARK --set-mark 60

Finally enable internet connection sharing:
$IPTABLES -A FORWARD -i ppp0 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPTABLES -A FORWARD -i eth0 -o ppp0 -j ACCEPT
$IPTABLES -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

[edit] Shaping the traffic using HTB

Now that we have got to this stage, we have all our traffic nicely marked. All we need to do now is shape it. Unfortunately ingress shaping on Linux is somewhat limited, so instead we only do egress shaping. To limit traffic coming in from the internet, we shape the traffic as it leaves the server. Not ideal, but it seems to work okay.
In these scripts I limit the downlink at 2200 kbps and the uplink at 330 kpbs. These figures *must* be less that your connection is capable of, otherwise no shaping will take place as the connection will do the shaping instead. The generally accepted approach is to set the values to 90% the theoretical maximum, but I advise you to experiment.
First, the downlink. Shaping is done on eth0 as the traffic leaves for the network.
We use HTB to do the shaping. It can be difficult to understand HTB and tc in general, but if you look hard enough there is some good documentation out there, it's just hard to find. I will place some links at the end of this document.
First, some basics. A qdisc is a whole set of shaping rules that we apply, normally to a whole interface. Here we add a HTB qdisc to the interface eth0. This is known as the root for the interface.
We don't set a default class; this is so that local eth0 traffic is not shaped. As already stated, we have to shape at eth0 and not ppp0 as we can only do egress shaping decently.
# Create the root qdisc on the interface
tc qdisc add dev eth0 root handle 1: htb

# Add some overall rate limits as defined above. Parent number 1:
# says to apply it to the root above. Call this child 1:1
tc class add dev eth0 parent 1: classid 1:1 htb rate 2200kbit
We now have one root HTB qdisc with a rate limit of 2200kbps. To this we add 4 further children. Note the numbers. 1: (or 1:0) is the root. 1:1 is the first child with the overall rate limit. Each child of this is 1:10, 1:20 and so on. To make things simpler, I have numbered the children below to align with the MARK numbers. Note that all the rates of the children should add up to the single rate limit of the parent.
# Add a number of classes to the root qdisc.
# With some qdiscs the classes are automatically
# created. With HTB they are not so we add 4 in total
# with different rate limits for each

# interactive traffic
tc class add dev eth0 parent 1:1  classid 1:10 htb \
 rate 100kbit ceil 100kbit prio 0

# web browsing
tc class add dev eth0 parent 1:1  classid 1:30 htb \
 rate 1000kbit ceil 1000kbit prio 1

# default traffic
tc class add dev eth0 parent 1:1  classid 1:40 htb \
 rate 1000kbit ceil 1000kbit prio 2

# bad boys
tc class add dev eth0 parent 1:1  classid 1:60 htb \
 rate 100kbit ceil 100kbit prio 3

We now have the HTB qdisc fully set up. However, no traffic will be sent to it yet, and the traffic will not be shaped within each class.
The next set of rules shape traffic in each class. If we don't do this, then all the traffic for a particular class (such as all the webbrowsing traffic - 30) will be piled into the class on a fifo basis. We want to be more intelligent than this. SFQ does some nice fair shaping.
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10
tc qdisc add dev eth0 parent 1:60 handle 60: sfq perturb 10
So, everything is set up and ready to go. We just need to divert some traffic into each of the classes. We do this by attaching a filter to the class. A filter looks for traffic of a particular type and sucks it into the class. In this example, we use the MARK of the traffic (called flowid here).
tc filter add dev eth0 parent 1:0 protocol ip handle 10 fw flowid 1:10
tc filter add dev eth0 parent 1:0 protocol ip handle 30 fw flowid 1:30
tc filter add dev eth0 parent 1:0 protocol ip handle 40 fw flowid 1:40
tc filter add dev eth0 parent 1:0 protocol ip handle 60 fw flowid 1:60
Everything will be working nicely at this point. However, we have one more tweak to do. We want to share traffic between clients (by IP address) not by connection. This means that if one client has 4 downloads on the go, and another has only one, that traffic will be split 50/50, as opposed to the first client getting 80%. We do this by applying more filters to the existing ones.
tc filter add dev eth0 parent 10: protocol ip handle 10 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 30: protocol ip handle 30 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 40: protocol ip handle 40 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 60: protocol ip handle 60 flow hash keys nfct-dst divisor 1024
That completes the downlink. The uplink (out on ppp0) is exactly the same. I have not repeated it here, but it is shown in the full example later.

[edit] The full script

The full script is the same script as used for the complete web portal / traffic shaping solution (detailed here). It can be downloaded from here.

[edit] References

A really well written overview of traffic shaping (chapter 2)
http://www.opalsoft.net/qos/DS.htm

HTB info and manual:
http://www.mikrotik.com/testdocs/ros/2.9/root/queue.php
http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm

Kernel traffic routing diagram - really handy
http://www.docum.org/docum.org/kptd/

Courtesy : http://www.andybev.com/index.php/Fair_traffic_shaping_an_ADSL_line_for_a_local_network_using_Linux 

tc iptables marking (htb shape)

# Script to shape up and downlink with traffic that is already MARKed

# Delete all old stuff first
tc qdisc del dev ppp0 root    2> /dev/null > /dev/null
tc qdisc del dev ifb0 root   2> /dev/null > /dev/null
tc qdisc del dev ifb0 ingress   2> /dev/null > /dev/null
tc qdisc del dev ppp0 root 2> /dev/null > /dev/null
tc qdisc del dev ifb0 root 2> /dev/null > /dev/null
tc qdisc del dev ppp0 ingress 2> /dev/null > /dev/null
tc qdisc del dev eth0 root 2> /dev/null > /dev/null
tc qdisc del dev eth0 ingress 2> /dev/null > /dev/null

# Set variables
# The downlink should be slightly less than the ADSL line
# All the classes below should add up to this
DOWNLINK=2200
# Same for the uplink
UPLINK=330

##############################################################################
## downlink via eth0 ##

# A qdisc is a whole set of shaping rules that we apply
# Here we add a HTB qdisc to the interface eth0
# This is known as the root for the interface
# We don't set a default class to stop us shaping local eth0 traffic
# We have to shape at eth0 and not ppp0 as we can only do egress shaping
tc qdisc add dev eth0 root handle 1: htb

# Then we add to the root some overall rate limits
tc class add dev eth0 parent 1: classid 1:1 htb rate ${DOWNLINK}kbit

# Then we go through and add a number of classes to the
# root qdisc. With some qdiscs the classes are automatically
# created. With HTB they are not so we add 4 in total
# with different rate limits for each

# interactive traffic
tc class add dev eth0 parent 1:1  classid 1:10 htb \
 rate 100kbit ceil 100kbit prio 0

# web browsing
tc class add dev eth0 parent 1:1  classid 1:30 htb \
 rate 1000kbit ceil 1000kbit prio 1

# default traffic
tc class add dev eth0 parent 1:1  classid 1:40 htb \
 rate 1000kbit ceil 1000kbit prio 2

# bad boys
tc class add dev eth0 parent 1:1  classid 1:60 htb \
 rate 100kbit ceil 100kbit prio 3

# Next we add some more qdiscs. These are different priority
# qdiscs but they each sit on top of the classes already created.
# So the root qdisc dumps traffic in each class, and the qdisc
# here prioritises within that class
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10 #flow hash keys dst divisor 1024 #hash ctorigsrc
tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10 #hash ctorigsrc
tc qdisc add dev eth0 parent 1:60 handle 60: sfq perturb 10 #hash ctorigsrc

# Finally we attach some filters to each class
# A filter is what sends a particular packet to a particular class
# This filter uses the iptables marks to allocate them
tc filter add dev eth0 parent 1:0 protocol ip handle 10 fw flowid 1:10
tc filter add dev eth0 parent 1:0 protocol ip handle 30 fw flowid 1:30
tc filter add dev eth0 parent 1:0 protocol ip handle 40 fw flowid 1:40
tc filter add dev eth0 parent 1:0 protocol ip handle 60 fw flowid 1:60

# These are additional filters that hash based on the client IP
# This means that rather than bandwidth being shared between
# several connections (so that one client could get several times
# the bandwidth), each client gets an equal slice of the bandwidth
# regardless of the number of connections they have
tc filter add dev eth0 parent 10: protocol ip handle 10 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 30: protocol ip handle 30 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 40: protocol ip handle 40 flow hash keys nfct-dst divisor 1024
tc filter add dev eth0 parent 60: protocol ip handle 60 flow hash keys nfct-dst divisor 1024

########################################## End of downlink configuration ##########################################



###################################################################################################################
## uplink via ppp0 ##

# A qdisc is a whole set of shaping rules that we apply
# Here we add a HTB qdisc to the interface ppp0
# This is known as the root for the interface
# Default class is 40
tc qdisc add dev ppp0 root handle 1: htb default 40

# Then we add to the root some overall rate limits
tc class add dev ppp0 parent 1: classid 1:1 htb rate ${UPLINK}kbit

# Then we go through and add a number of classes to the
# root qdisc. With some qdiscs the classes are automatically
# created. With HTB they are not so we add 4 in total
# with different rate limits each

# interactive traffic
tc class add dev ppp0 parent 1:1  classid 1:10 htb \
 rate 50kbit ceil 50kbit prio 0

# web browsing
tc class add dev ppp0 parent 1:1  classid 1:30 htb \
 rate 120kbit ceil 200kbit prio 1

# default traffic
tc class add dev ppp0 parent 1:1  classid 1:40 htb \
 rate 120kbit ceil 200kbit prio 2

# bad boys
tc class add dev ppp0 parent 1:1  classid 1:60 htb \
 rate 40kbit ceil 40kbit prio 3

# Next we add some more qdiscs. These are different priority
# qdiscs but they each sit on top of the classes already created.
# So the root qdisc dumps traffic in each class, and the qdisc
# here prioritises within that class
tc qdisc add dev ppp0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev ppp0 parent 1:30 handle 30: sfq perturb 10
tc qdisc add dev ppp0 parent 1:40 handle 40: sfq perturb 10 
tc qdisc add dev ppp0 parent 1:60 handle 60: sfq perturb 10

# Finally we attach some filters to each class
# A filter is what sends a particular packet to a particular class
# This filter uses the iptables marks to allocate them
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 30 fw flowid 1:30
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 40 fw flowid 1:40
tc filter add dev ppp0 parent 1:0 prio 0 protocol ip handle 60 fw flowid 1:60

# see download comment
tc filter add dev ppp0 parent 10: protocol ip handle 10 flow hash keys nfct-src divisor 1024
tc filter add dev ppp0 parent 30: protocol ip handle 30 flow hash keys nfct-src divisor 1024
tc filter add dev ppp0 parent 40: protocol ip handle 40 flow hash keys nfct-src divisor 1024
tc filter add dev ppp0 parent 60: protocol ip handle 60 flow hash keys nfct-src divisor 1024

################################# End of uplink configuration #####################################################
 
Courtesy : http://files.andybev.com/web-portal/shape-htb

Saturday, September 11, 2010

A shell script to measure network throughput on Linux machines

Here is a shell script to see how many (kilo-, mega-, giga-, terra-) bytes pass a network interface.

The output looks like this:

$ ./network-traffic.sh --help
Usage: ./network-traffic.sh [-i INTERFACE] [-s INTERVAL] [-c COUNT]

-i INTERFACE
    The interface to monitor, default is eth0.
-s INTERVAL
    The time to wait in seconds between measurements, default is 3 seconds.
-c COUNT
    The number of times to measure, default is 10 times.
$ ./network-traffic.sh        
Monitoring eth0 every 3 seconds. (RXbyte total = 706 Mb TXbytes total = 1 Gb)
RXbytes = 104 b TXbytes = 194 b
RXbytes = 80 b TXbytes = 188 b
RXbytes = 52 b TXbytes = 146 b
RXbytes = 689 b TXbytes = 8 Kb
RXbytes = 52 b TXbytes = 146 b
RXbytes = 52 b TXbytes = 146 b
RXbytes = 52 b TXbytes = 146 b
RXbytes = 52 b TXbytes = 146 b
RXbytes = 4 Kb TXbytes = 4 Kb
RXbytes = 716 b TXbytes = 5 Kb
Here is the script:

#!/bin/sh

usage(){
echo "Usage: $0 [-i INTERFACE] [-s INTERVAL] [-c COUNT]"
echo
echo "-i INTERFACE"
echo "    The interface to monitor, default is eth0."
echo "-s INTERVAL"
echo "    The time to wait in seconds between measurements, default is 3 seconds."
echo "-c COUNT"
echo "    The number of times to measure, default is 10 times."
exit 3
}

readargs(){
while [ "$#" -gt 0 ] ; do
  case "$1" in
   -i)
    if [ "$2" ] ; then
     interface="$2"
     shift ; shift
    else
     echo "Missing a value for $1."
     echo
     shift
     usage
    fi
   ;;
   -s)
    if [ "$2" ] ; then
     sleep="$2"
     shift ; shift
    else
     echo "Missing a value for $1."
     echo
     shift
     usage
    fi
   ;;
   -c)
    if [ "$2" ] ; then
     counter="$2"
     shift ; shift
    else
     echo "Missing a value for $1."
     echo
     shift
     usage
    fi
   ;;
   *)
    echo "Unknown option $1."
    echo
    shift
    usage
   ;;
  esac
done
}

checkargs(){
if [ ! "$interface" ] ; then
  interface="eth0"
fi
if [ ! "$sleep" ] ; then
  sleep="3"
fi
if [ ! "$counter" ] ; then
  counter="10"
fi
}

printrxbytes(){
/sbin/ifconfig "$interface" | grep "RX bytes" | cut -d: -f2 | awk '{ print $1 }'
}

printtxbytes(){
/sbin/ifconfig "$interface" | grep "TX bytes" | cut -d: -f3 | awk '{ print $1 }'
}

bytestohumanreadable(){
multiplier="0"
number="$1"
while [ "$number" -ge 1024 ] ; do
  multiplier=$(($multiplier+1))
  number=$(($number/1024))
done
case "$multiplier" in
  1)
   echo "$number Kb"
  ;;
  2)
   echo "$number Mb"
  ;;
  3)
   echo "$number Gb"
  ;;
  4)
   echo "$number Tb"
  ;;
  *)
   echo "$1 b"
  ;;
esac
}
 
printresults(){
while [ "$counter" -ge 0 ] ; do
  counter=$(($counter - 1))
  if [ "$rxbytes" ] ; then
   oldrxbytes="$rxbytes"
   oldtxbytes="$txbytes"
  fi
  rxbytes=$(printrxbytes)
  txbytes=$(printtxbytes)
  if [ "$oldrxbytes" -a "$rxbytes" -a "$oldtxbytes" -a "$txbytes" ] ; then
   echo "RXbytes = $(bytestohumanreadable $(($rxbytes - $oldrxbytes))) TXbytes = $(bytestohumanreadable $(($txbytes - $oldtxbytes)))"
  else
   echo "Monitoring $interface every $sleep seconds. (RXbyte total = $(bytestohumanreadable $rxbytes) TXbytes total = $(bytestohumanreadable $txbytes))"
  fi
  sleep "$sleep"
done
}

readargs "$@"
checkargs
printresults


Courtesy : http://meinit.nl/shell-script-measure-network-throughput-linux-machines

Monday, September 6, 2010

more netroute2 hacks – new traffic shaper

On my previous post, more netroute2 hacks – high availability, one of the changed files was the dial_conn file. At the end of the diff there was a line with a # in front:
+ sleep 5
+ #/etc/bin/wshaper ppp0 192 1024

Inside netroute2 one can find the /etc-ro/ppp/wshaper file which is the traffic shaping script of the modem/router. Unfortunately it resides in the read-only section of the router so you can’t make changes directly to it. What I did was to make a copy of it on the writable /etc/bin/ and change a line in my /etc/bin/dial_conn to call it from there, right after (5 seconds later) the connection with the ISP has been established.
If you have followed the previous post about high availability the only thing you need to change is to edit your /etc/bin/dial_conn file and remove the # from the live above. Else…read the previous post :)
The first argument of the script is the device the rules will apply to, the second argument is the upload speed and the third is the download speed. Netroute2’s own traffic shaping script gets the 3 arguments while syncing with the dslam. The problem with adsl lines here in Greece, and I guess in many other countries as well, is that the speed the modem syncs with the dslam has nothing to do with the real speed you actually get. So shaping for 256kbit upload while never reaching more than 200 is a bit foolish imho. What I did was lower the upload so that I am always (or mostly always) sure that this is my max upload speed at the time. I can now create rules based on the assumption that my upload speed is 192kbit. If the upload speed your modem syncs is 192kbit I would advise you not to put more than 128kbit as the first argument. It’s a trial and error situation.
While lowering my shaped upload speed and keeping the rest of the script intact already made a difference I knew that I could do some more tweaking.
The first thing one has to know before creating any traffic shaping script is to learn what the TOS field is:
#TOS FIELD
# 0×10 – (minimize delay)
# 0×08 (maximize throughput),
# 0×04 (maximize reliability),
# 0×02 (minimize cost)
# 0×00 (best effort)
You can then create rules with iptables to change the TOS field of certain packets, for example:
$IPTABLES -t mangle -A POSTROUTING -o $DEV -p tcp --syn -m length --length 40:68 -j TOS --set-tos 0x10
$IPTABLES -t mangle -A POSTROUTING -o $DEV -p tcp --tcp-flags ALL ACK,FIN -j TOS --set-tos 0x10

A great rule to add to any of your scripts is to speed up ACK packets,(2) by adding them to the highest priority class (on netroute2 that’s 1:10):
$TC filter add dev $DEV parent 1: protocol ip prio 1 u32 \
match ip protocol 6 0xff \
match u8 0x05 0x0f at 0 \
match u16 0x0000 0xffc0 at 2 \
match u8 0x10 0xff at 33 \
flowid 1:10

What is also very very helpfull is to specify the port your torrent client uses (eg 17777) and add it to the lowest priority class (on netroute2 that 1:30):
$TC filter add dev $DEV parent 1:0 protocol ip prio 3 u32 match ip sport 17777 0xffff flowid 1:30
$TC filter add dev $DEV parent 1:0 protocol ip prio 3 u32 match ip dport 17777 0xffff flowid 1:30

Of course you can create your own classes inside /etc/bin/wshaper. If you are carefull enough with the rules you add you will be more than happy with the result :)
To monitor how your traffic shaping is going you can download a great perl script from here: http://qos.kallenberg.dk/ called qos.pl. This script reads a machine’s qos classes and priorities and creates graphs like the ones on the site. The problem with netroute2 is that it doesn’t have perl included, so one has to modify qos.pl to make it read netroute2’s qos performance while running from another machine. This is done by making the script run its commands through ssh-ing to netroute2 using public key auth. If you don’t know how to enable this on netroute2 please read part F of my older post: Intracom netroute2 hacks/.
What you need to change on the qos.pl script is:
a) change the $tc line with something like this:
$tc = "ssh root\@NETROUTE2.IP.GOES.HERE /usr/sbin/tc";
b) Find any occurances of “eth2″ and replace with “ppp0″ (there must be 2 occurances only).
now run the qos.pl script and it will start creating some graphs (png files) and an index.html on the directory from which you executed it. qos.pl depends on gnuplot, so you must install it before you run it.
The graphs are a great visual aid to to tweak your new traffic shaping script more and more.

Source : http://www.void.gr/kargig/blog/2007/07/12/more-netroute2-hacks-new-traffic-shaper/
During some QoS tests on Linux I needed to measure the traffic of the system in realtime without being able to compile any new software on it. The system had already perl installed so I googled to find a script that could monitor in/out traffic of an interface. The first script I found was this: http://perlmonks.org/?node_id=635792
While it’s actually doing what it says, it only runs just once. I wanted the script to run for a period of time. So I changed it a bit.
Here’s the outcome:
#!/usr/bin/perl
my $dev=$ARGV[0];
sub get_measures {
my $data = `cat /proc/net/dev | grep "$dev" | head -n1`;
$data =~ /$dev\:(\d+)\D+\d+\D+\d+\D+\d+\D+\d+\D+\d+\D+\d+\D+\d+\D+(\d+)\D+/;
my $recv = int($1/1024);
my $sent= int($2/1024);
return ($recv,$sent);
}
my @m1 = get_measures;
while(1) {
sleep 1;
my @m2 = get_measures;
my @rates = ($m2[0] - $m1[0], $m2[1]-$m1[1]);
foreach ('received' , ' transmit') {
printf "$_ rate:%sKB",shift @rates;
}
print "\n";
@m1=@m2;
}

I’ve changed it so that it’s:
a) running continuously until someone presses ctrl+c to stop it,
b) parsing the /proc/net/dev output instead of the ifconfig output. I think this is more efficient/fast than parsing the ifconfig output.
Sample output:
$iftraffic.pl eth0
received rate:1564KB transmit rate:71KB
received rate:1316KB transmit rate:44KB
received rate:1415KB transmit rate:48KB
received rate:1579KB transmit rate:76KB
I am sure that someone with more insight into perl than me can make it even more efficient.
You can also download a version with comments that I made so that one can make the script run for X number of repetitions instead of running until someone stops it.
http://www.void.gr/kargig/blog/wp-content/iftraffic.pl

Source : http://www.void.gr/kargig/blog/2009/05/04/iftraffic-perl-script-to-measure-inout-traffic-in-realtime/

traffic shaping a dsl line with linux

The case is like this:
[code]
Internet < --> [dsl modem] < --> [linux box] < --> [Lan]
[/code]
DSL modem is connected on eth2 on linux box and the rest of the Lan on eth0. I had a serious problem with people leaving edonkey clients opens all night..limiting the download speed to 20kb/sec but forgetting to limit the upload. The current dsl line is 384/128 so having the uploads unlimited…is like killing the line.
The solution was to setup a QOS script. And here it is:
[code]
#!/bin/bash
DEV="eth2"
LOCALIF="eth2"
# Reset everything to a known state (cleared)
tc qdisc del dev $DEV root 2> /dev/null > /dev/null
tc qdisc del dev imq0 root 2> /dev/null > /dev/null
iptables -t mangle -F POSTROUTING 2> /dev/null > /dev/null
iptables -t mangle -Z POSTROUTING 2> /dev/null > /dev/null
iptables -t mangle -X POSTROUTING 2> /dev/null > /dev/null
iptables -t mangle -F tosfix
iptables -t mangle -F ack
ip link set imq0 down 2> /dev/null > /dev/null
rmmod imq 2> /dev/null > /dev/null
if [ "$1" = "stop" ]
then
echo "Shaping removed on $DEV."
exit
fi
tc qdisc add dev $DEV root handle 1: tbf rate 85kbit burst 1600 limit 1
tc qdisc add dev $DEV parent 1:1 handle 2: prio bands 4
tc qdisc add dev $DEV parent 2:1 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 2:2 handle 20: sfq perturb 10
tc qdisc add dev $DEV parent 2:3 handle 30: sfq perturb 10
tc qdisc add dev $DEV parent 2:4 handle 40: tbf rate 40kbit burst 1600 limit 3000
tc qdisc add dev $DEV parent 40:1 handle 41: pfifo limit 10
iptables -t mangle -N tosfix
iptables -t mangle -A tosfix -p tcp -m length --length 0:64 -j RETURN
iptables -t mangle -A tosfix -m limit --limit 2/s --limit-burst 10 -j RETURN
iptables -t mangle -A tosfix -j TOS --set-tos Maximize-Throughput
iptables -t mangle -A tosfix -j RETURN
iptables -t mangle -N ack
iptables -t mangle -A ack -m tos ! --tos Normal-Service -j RETURN
iptables -t mangle -A ack -p tcp -m length --length 0:64 \
-j TOS --set-tos Minimize-Delay
iptables -t mangle -A ack -p tcp -m length --length 64: \
-j TOS --set-tos Maximize-Throughput
iptables -t mangle -A ack -j RETURN
# Is our TOS broken? Fix it for TCP ACK and OpenSSH.
iptables -t mangle -A POSTROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK ACK -j ack
iptables -t mangle -A POSTROUTING -p tcp -m tos --tos Minimize-Delay -j tosfix
# Here we deal with ACK, SYN, and RST packets
# Match SYN and RST packets
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp -m tcp --tcp-flags ! SYN,RST,ACK ACK \
-j CLASSIFY --set-class 2:1
# Match ACK packets
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp -m tcp --tcp-flags SYN,RST,ACK ACK \
-m length --length :128 -m tos --tos Minimize-Delay \
-j CLASSIFY --set-class 2:1
# Match packets with TOS Minimize-Delay
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp -m tos --tos Minimize-Delay \
-j CLASSIFY --set-class 2:1
### Actual traffic shaping classifications with CLASSIFY
# ICMP (ping)
iptables -t mangle -A POSTROUTING -o $LOCALIF -p icmp -j CLASSIFY --set-class 2:1
# Outbound client requests for HTTP, IRC and AIM (dport matches)
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp --dport 80 -j CLASSIFY --set-class 2:2
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp --dport 6667 -j CLASSIFY --set-class 2:2
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp --dport 5190 -j CLASSIFY --set-class 2:2
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp --sport 80 -j CLASSIFY --set-class 2:3
iptables -t mangle -A POSTROUTING -o $LOCALIF -p tcp --dport 1024: -j CLASSIFY --set-class 2:4
[/code]

It WORKS for me…I don’t know whether it will work for you though. I take no responsibility. I will explain it no further because comments do exists and it’s really easy to understand what’s going on if you read a couple of tc tutorials from the net. Many ideas about this script were “stolen” from other scripts I studied while trying to make mine.
Have fun with it…

Source : http://www.void.gr/kargig/blog/2005/07/27/traffic-shaping-a-dsl-line-with-linux/

Traffic Shaping (Explanation 1)

The most fundamental question is why is it necessary traffic regulation or traffic shaping?

   
1. You use your home office speedy to three computers. You do not need traffic shapping.
   
2. You use FastNet 384 kbps at home for three computers. You do not need traffic shapping.
   
3. If your users and your bandwidth is a little big, tell your users 100, 8 Mbps symmetris your bandwidth, you seem to not need traffic shaping (especially if it's also debatable use voip or video conferencing).
   
4. If your users only one to five people can say you do not need traffic shaping, because your bandwidth is still sufficient to serve your users. But what if your users more than 15 people and each perform a remote ssh connection, in addition to browse and download. You could say you'll have a problem, if you do not shape traffic to upload and create policy for your downlink. I experienced it myself with about 60 users of bandwidth-hungry.
   
5. Maintain low latency for interactive traffic. This means that the process of downloading and uploading should not disturb SSH, telnet and the like. It is the most important. With a latency of 200ms is enough to make working with SSH very uncomfortable.
   
6. Keeping the user can still browse the internet with a comfortable speed while doing the uploading or downloading.
   
7. Ensuring that the upload process does not compromise the process of downloading and vice versa. Please understand that there is a big queue at the device like a cable modem or ADSL modem will make uploading, downloading and interactive traffic will play each other each other.
In my previous article, I gave the script to perform traffic shaping in openSUSE (well, also for other Linux distributions). Now I will explain what the intent of the script. When was the first time to learn tc, ip, and HTB I realized that this was the most difficult.

#!/bin/sh
#
#
# /etc/init.d/mebwshaper_eth1
#
### BEGIN INIT INFO
# Provides:          mebwshaper_eth1
# Required-Start:    $network
# Should-Start:
# Required-Stop:
# Should-Stop:
# Default-Start:     3 5
# Default-Stop:      0 1 2 6
# Short-Description: Custom bandwidth shaping by medwinz@gmail.com
# Description:       Custom bandwidth shaping by medwinz@gmail.com
### END INIT INFO
#
 Courtesy : http://medwinz.blogsome.com/2008/11/18/traffic-shaping-lagi-huh/