Showing posts with label traffic shaping. Show all posts
Showing posts with label traffic shaping. Show all posts

Thursday, August 25, 2011

linux filters and queuing discipline

TC is used to configure traffic control in Linux kernel. Traffic control consists of the following:
1) Shaping: Shaping is done at the outgoing interface, and includes throttling the bandwidth and/or smoothing the traffic bursts of the outgoing flows.
2) Scheduling: Scheduling is also done at the outgoing interface and makes it possible to improve interactivity for traffic that needs it while still guaranteeing bandwidth to bulk transfers.
3) Policing: Policing is done at the ingress and is primarily used for throttling the rate at which flows may arrive. Dropping is a severe form of policing.

Thursday, May 26, 2011

manipulate traffic control settings

TC(8)                         Linux                         TC(8)



NAME
       tc - show / manipulate traffic control settings

SYNOPSIS
       tc  qdisc [ add | change | replace | link ] dev DEV [ par-
       ent qdisc-id | root ] [ handle qdisc-id ]  qdisc  [  qdisc
       specific parameters ]


       tc  class [ add | change | replace ] dev DEV parent qdisc-
       id [ classid class-id ] qdisc [ qdisc specific  parameters
       ]


       tc  filter  [  add  |  change | replace ] dev DEV [ parent
       qdisc-id | root ] protocol protocol prio priority  filter-
       type [ filtertype specific parameters ] flowid flow-id

       tc [-s | -d ] qdisc show [ dev DEV ]

       tc [-s | -d ] class show dev DEV

       tc filter show dev DEV


DESCRIPTION
       Tc  is used to configure Traffic Control in the Linux ker-
       nel. Traffic Control consists of the following:


       SHAPING
              When traffic is shaped, its rate of transmission is
              under  control.  Shaping  may be more than lowering
              the available bandwidth - it is also used to smooth
              out bursts in traffic for better network behaviour.
              Shaping occurs on egress.


       SCHEDULING
              By scheduling the transmission  of  packets  it  is
              possible  to improve interactivity for traffic that
              needs it while still guaranteeing bandwidth to bulk
              transfers.  Reordering is also called prioritizing,
              and happens only on egress.


       POLICING
              Where shaping deals with transmission  of  traffic,
              policing  pertains  to  traffic  arriving. Policing
              thus occurs on ingress.


       DROPPING
              Traffic exceeding  a  set  bandwidth  may  also  be
              dropped forthwith, both on ingress and on egress.


       Processing  of  traffic  is  controlled  by three kinds of
       objects: qdiscs, classes and filters.


QDISCS
       qdisc is short for 'queueing discipline' and it is elemen-
       tary to understanding traffic control. Whenever the kernel
       needs to send a packet to an interface, it is enqueued  to
       the  qdisc  configured  for  that  interface.  Immediately
       afterwards, the kernel tries to get  as  many  packets  as
       possible  from  the  qdisc, for giving them to the network
       adaptor driver.

       A simple QDISC is the 'pfifo' one, which does no  process-
       ing  at  all  and  is a pure First In, First Out queue. It
       does however store  traffic  when  the  network  interface
       can't handle it momentarily.


CLASSES
       Some  qdiscs  can  contain  classes, which contain further
       qdiscs - traffic may then be enqueued in any of the  inner
       qdiscs,  which  are  within  the classes.  When the kernel
       tries to dequeue a packet from such a  classful  qdisc  it
       can  come from any of the classes. A qdisc may for example
       prioritize certain kinds of traffic by trying  to  dequeue
       from certain classes before others.


FILTERS
       A filter is used by a classful qdisc to determine in which
       class a packet will be enqueued. Whenever traffic  arrives
       at  a  class  with  subclasses, it needs to be classified.
       Various methods may be employed to do so, one of these are
       the filters. All filters attached to the class are called,
       until one of them returns with a verdict.  If  no  verdict
       was  made,  other  criteria may be available. This differs
       per qdisc.

       It is important  to  notice  that  filters  reside  within
       qdiscs - they are not masters of what happens.


CLASSLESS QDISCS
       The classless qdiscs are:

       [p|b]fifo
              Simplest  usable  qdisc,  pure  First In, First Out
              behaviour. Limited in packets or in bytes.

       pfifo_fast
              Standard qdisc for 'Advanced Router'  enabled  ker-
              nels.  Consists  of a three-band queue which honors
              Type of Service flags, as well as the priority that
              may be assigned to a packet.

       red    Random  Early  Detection simulates physical conges-
              tion by randomly dropping packets when nearing con-
              figured  bandwidth  allocation. Well suited to very
              large bandwidth applications.

       sfq    Stochastic Fairness Queueing reorders queued  traf-
              fic  so  each  'session'  gets  to send a packet in
              turn.

       tbf    The Token Bucket Filter is suited for slowing traf-
              fic  down  to  a  precisely configured rate. Scales
              well to large bandwidths.

CONFIGURING CLASSLESS QDISCS
       In the absence of classful qdiscs,  classless  qdiscs  can
       only be attached at the root of a device. Full syntax:

       tc qdisc add dev DEV root QDISC QDISC-PARAMETERS

       To remove, issue

       tc qdisc del dev DEV root

       The  pfifo_fast  qdisc  is  the  automatic  default in the
       absence of a configured qdisc.


CLASSFUL QDISCS
       The classful qdiscs are:

       CBQ    Class Based Queueing implements a rich  linksharing
              hierarchy of classes.  It contains shaping elements
              as well as prioritizing  capabilities.  Shaping  is
              performed  using  link idle time calculations based
              on average packet size and  underlying  link  band-
              width.  The  latter  may  be  ill-defined  for some
              interfaces.

       HTB    The  Hierarchy  Token  Bucket  implements  a   rich
              linksharing  hierarchy  of classes with an emphasis
              on conforming to existing  practices.  HTB  facili-
              tates guaranteeing bandwidth to classes, while also
              allowing specification of upper  limits  to  inter-
              class  sharing. It contains shaping elements, based
              on TBF and can prioritize classes.

       PRIO   The PRIO qdisc is a  non-shaping  container  for  a
              configurable  number  of classes which are dequeued
              in order. This allows for  easy  prioritization  of
              traffic,  where lower classes are only able to send
              if higher ones have no packets available. To facil-
              itate  configuration, Type Of Service bits are hon-
              ored by default.

THEORY OF OPERATION
       Classes form a tree, where each class has a single parent.
       A  class may have multiple children. Some qdiscs allow for
       runtime addition of classes (CBQ, HTB) while others (PRIO)
       are created with a static number of children.

       Qdiscs  which  allow  dynamic addition of classes can have
       zero or more subclasses to which traffic may be  enqueued.

       Furthermore,  each  class  contains  a leaf qdisc which by
       default has pfifo behaviour though another  qdisc  can  be
       attached  in  place. This qdisc may again contain classes,
       but each class can have only one leaf qdisc.

       When a packet enters a classful qdisc it can be classified
       to  one  of  the classes within. Three criteria are avail-
       able, although not all qdiscs will use all three:

       tc filters
              If tc filters are attached to  a  class,  they  are
              consulted  first for relevant instructions. Filters
              can match on all fields of a packet header, as well
              as on the firewall mark applied by ipchains or ipt-
              ables. See tc-filters(8).

       Type of Service
              Some qdiscs have built  in  rules  for  classifying
              packets based on the TOS field.

       skb->priority
              Userspace  programs  can  encode  a class-id in the
              'skb->priority' field using the SO_PRIORITY option.

       Each  node  within  the  tree can have its own filters but
       higher level filters may  also  point  directly  to  lower
       classes.

       If classification did not succeed, packets are enqueued to
       the leaf qdisc attached to that class.  Check  qdisc  spe-
       cific manpages for details, however.


NAMING
       All qdiscs, classes and filters have IDs, which can either
       be specified or be automatically assigned.

       IDs consist of a major number and a  minor  number,  sepa-
       rated by a colon.


       QDISCS A  qdisc, which potentially can have children, gets
              assigned a major number, called a 'handle', leaving
              the  minor  number namespace available for classes.
              The handle is expressed as '10:'.  It is  customary
              to explicitly assign a handle to qdiscs expected to
              have children.


       CLASSES
              Classes residing under a qdisc  share  their  qdisc
              major number, but each have a separate minor number
              called a 'classid' that has no  relation  to  their
              parent  classes,  only  to  their parent qdisc. The
              same naming custom as for qdiscs applies.


       FILTERS
              Filters have a three part ID, which is only  needed
              when using a hashed filter hierarchy, for which see
              tc-filters(8).

UNITS
       All parameters accept a floating  point  number,  possibly
       followed by a unit.

       Bandwidths or rates can be specified in:

       kbps   Kilobytes per second

       mbps   Megabytes per second

       kbit   Kilobits per second

       mbit   Megabits per second

       bps or a bare number
              Bytes per second

       Amounts of data can be specified in:

       kb or k
              Kilobytes

       mb or m
              Megabytes

       mbit   Megabits

       kbit   Kilobits

       b or a bare number
              Bytes.

       Lengths of time can be specified in:

       s, sec or secs
              Whole seconds

       ms, msec or msecs
              Milliseconds

       us, usec, usecs or a bare number
              Microseconds.


TC COMMANDS
       The  following  commands are available for qdiscs, classes
       and filter:

       add    Add a qdisc, class or filter to  a  node.  For  all
              entities,  a parent must be passed, either by pass-
              ing its ID or by attaching directly to the root  of
              a  device.   When  creating a qdisc or a filter, it
              can be named with the handle parameter. A class  is
              named with the classid parameter.


       remove A  qdisc  can  be removed by specifying its handle,
              which may also be 'root'. All subclasses and  their
              leaf  qdiscs  are automatically deleted, as well as
              any filters attached to them.


       change Some entities can be modified  'in  place'.  Shares
              the  syntax  of  'add', with the exception that the
              handle cannot be changed and neither can  the  par-
              ent. In other words, change cannot move a node.


       replace
              Performs  a nearly atomic remove/add on an existing
              node id. If the node does not exist yet it is  cre-
              ated.


       link   Only  available  for  qdiscs and performs a replace
              where the node must exist already.



HISTORY
       tc was written by Alexey N. Kuznetsov and added  in  Linux
       2.2.

SEE ALSO
       tc-cbq(8), tc-htb(8), tc-sfq(8), tc-red(8), tc-tbf(8), tc-
       pfifo(8), tc-bfifo(8), tc-pfifo_fast(8), tc-filters(8)


AUTHOR
       Manpage maintained by bert hubert (ahu@ds9a.nl)

iproute2                 16 December 2001                   TC(8)
http://yesican.chsoft.biz/lartc/tc.html

A Practical Guide to Linux Traffic Control

4. Class Structure Revealed

Paramount to creating a useful traffic control configuration is understanding how to manipulate the class hierarchy you can attach to each root hook. You configure all aspects of the actual shaping using the tc binary. (Traffic classification can be done with the tc binary as well, but we will instead look at a more powerful method later.)

4.1. A Classless qdisc

Let us take an example, using the tc binary.

tc qdisc add dev eth2 parent root handle 1:0 pfifo
Now, that is a lot to take in at once. I have added some verbosity you seldom see to further attempt to clarify what is happening here.
First, we specify that we want to work with a qdisc. Next, we indicate we wish to add a new qdisc to the Ethernet device eth2. (You can specify del in place of add to remove the qdisc in question.) Then, we specify the special parent root. We discussed the importance of the root hook earlier. It is the hook on the egress side of your Ethernet interface. The handle is the magic userspace way of naming a particular qdisc, but more on that later. Finally, we specify the qdisc we wish to add. Because pfifo is a classless qdisc, there is nothing more to do.
A graphical representation of the structure we just created is depicted below. The color blue is used to represent a qdisc. Later, you will see green used to represent a class.

It is important to discuss the naming convention for qdiscs before proceeding. qdiscs are always referred to using a combination of a major node number and a minor node number. For any given qdisc, the major node number has to be unique for the root hook for a given Ethernet interface. The minor number for any given qdisc will always be zero. By convention, the first qdisc created is named 1:0. You could, however, choose 7:0 instead. These numbers are actually in hexadecimal, so any values in within the range of 1 to ffff are also valid. For readability the digits 0 to 9 are generally used exclusively.

4.2. A Classful qdisc

Now, let us look at an example where we add a classful qdisc and a single class.

tc qdisc add dev eth2 parent root handle 1:0 htb default 1
Initially, it looks almost identical to the previous classless qdisc. The htb qdisc was used here. However, to actually benefit from using this classful qdisc, we need to add some classes. You will notice above the parameter default is specified. It is an option for htb qdiscs described later.

tc class add dev eth2 parent 1:0 classid 1:1 htb rate 1mbit
Now, we use the tc binary with the class argument, instead of the qdisc argument. The class argument allows you to create a class hierarchy. We are working with Ethernet device eth2 again. The parent parameter enables you to attach this class to either an existing classful qdisc or another class of the same type. Above we attach to the htb qdisc we just attached to the root hook earlier.
The value for the parent parameter must be the major and minor node number of the qdisc or class you wish to attach to. Earlier, the identifier 1:0 was chosen for handle of the htb qdisc. That must be used as the argument to the parent parameter so tc knows where you are assigning this class.
The classid parameter serves the same purpose for classes that the handle parameter serves for qdiscs. It is the identifier for this specific class. The major node number has already been chosen for you. It must be the same as the major node number specified for the parent argument earlier. You are free to choose any minor node number you want for the classid parameter. Traditionally numbering starts at 1, but numbers from 1 to ffff are valid. For this class the classid 1:1 was chosen, because the qdisc it is being attached to has a major node number 1 for its handle parameter.
Finally we specify the type of class and any options that class requires. In this instance, the htb class was chosen, as the htb qdisc can only have htb classes assigned to it. (This is generally true of classful qdiscs.) The rate option for htb is discussed later.
Another graphical representation, this time of an htb qdisc and an associated class in a simple hierarchy, is shown below. The qdisc is blue and the class green.

4.3. A Combined Example

Finally, we can reveal a complete example using both classful and classless qdiscs.

tc qdisc add dev eth2 parent root handle 1:0 htb default 20
tc class add dev eth2 parent 1:0 classid 1:1 htb rate 1000kbit
tc class add dev eth2 parent 1:1 classid 1:10 htb rate 500kbit
tc class add dev eth2 parent 1:1 classid 1:20 htb rate 500kbit
tc qdisc add dev eth2 parent 1:20 handle 2:0 sfq
Now we have a nested structure, with a htb classful qdisc assigned to the root hook, three htb classes, and asfq qdisc as a leaf qdisc for one htb class. The other has an implicit pfifo attached. The careful reader will notice each qdisc has a minor node number of zero, as is required.
A graphical representation of the class hierarchy just created should be beneficial.

First, notice the at the top of the hierarchy is a htb qdisc. Three classes are assigned to it. Only the first is immediately attached to it, using the parent 1:0. The other two classes are children of the first class. If you examine the tc command with the class option, you will see that the parent refers to the parent class in the hierarchy via its classid.
Each of the three htb classes attached to the htb qdisc are assigned a major node number of 1 for the classid, as the qdisc they are attached to has a handle with 1 as the major node number. The minor node number for each classid must merely be a unique number between 1 and ffff in hexadecimal.
Finally, a sfq qdisc is attached to the leaf class with classid 1:20. Notice the qdisc is added nearly the same as the htb. However, instead of being assigned to the magic root hook, the target is 1:20. The handle is chosen based on the rules discussed earlier. Briefly, the major node number must be a unique number between 1 and ffff and the minor node must be 0.
Last, the whole structure can be deleted simply by deleting the root hook as demonstrated below.

tc qdisc del dev eth2 root

4.4. Displaying qdisc and class Details

Now we can take a look at the details of the hierarchy we have created. Using the tc tool again the following output is produced.

# tc -s -d qdisc show dev eth2
qdisc sfq 2: quantum 1514b limit 128p flows 128/1024
 Sent 0 bytes 0 pkts (dropped 0, overlimits 0)

qdisc htb 1: r2q 10 default 0 direct_packets_stat 0 ver 3.16
 Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
Each qdisc in your hierarchy is shown along with statistics and the details of its parameters. The information available for each qdisc varies. The number of sent bytes and packets is self explanatory. For classful qdiscs, the totals are class wide and include the dequeue totals from children and siblings.

# tc -s -d class show dev eth2
class htb 1:10 root leaf 2: prio 0 quantum 13107 rate 1Mbit ceil 1Mbit
  burst 2909b/8 mpu 0b cburst 2909b/8 mpu 0b level 0
 Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
 lended: 0 borrowed: 0 giants: 0
 tokens: 28791 ctokens: 2879
The detailed output for classes is similar to that of qdiscs. The information available varies depending on the type of class. The above is typical of a htb qdisc's class.
Next, we will discuss some of the more interesting qdiscs available, including pfifo, sfq, tbf, prio, htb.

PrevHomeNext
Linux Traffic Control

hfsc script

tc qdisc add dev $DEV root handle 1: hfsc default 10
tc class add dev $DEV parent 1: classid 1:1 hfsc sc rate 3072kbit ul rate 3072kbit
tc class add dev $DEV parent 1:1 classid 1:10 hfsc sc umax 1500b dmax 53ms rate 614kbit ul rate 3072kbit
tc class add dev $DEV parent 1:1 classid 1:11 hfsc sc umax 1500b dmax 30ms rate 2457kbit ul rate 3072kbit

iptables -t mangle --new-chain voip
iptables -t mangle --insert voip -o $DEV -j voip

tc filter add dev $DEV parent 1: prio 1 protocol ip handle 1 fw flowid 1:11

iptables -t mangle -A voip -p udp --sport 4569 -j MARK --set-mark 1
iptables -t mangle -A voip -p udp --dport 4569 -j MARK --set-mark 1

iptables -t mangle -A voip -p udp --sport 5060 -j MARK --set-mark 1
iptables -t mangle -A voip -p udp --dport 5060 -j MARK --set-mark 1


iptables -t mangle -A voip -p udp --sport 10000:20000 -j MARK --set-mark 1
iptables -t mangle -A voip -p udp --dport 10000:20000 -j MARK --set-mark 1




tc -s qdisc show eth0
qdisc hfsc 1: root refcnt 2 default 10
Sent 83509933 bytes 1029276 pkt (dropped 3, overlimits 6238 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0

tc -s class show dev
class hfsc 1: root
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
period 0 level 2

class hfsc 1:11 parent 1:1 sc m1 0bit d 25.1ms m2 2457Kbit ul m1 0bit d 0us m2 3072Kbit
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
period 0 level 0

class hfsc 1:1 parent 1: sc m1 0bit d 0us m2 3072Kbit ul m1 0bit d 0us m2 3072Kbit
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
period 1029159 work 83510091 bytes level 1

class hfsc 1:10 parent 1:1 sc m1 0bit d 33.5ms m2 614000bit ul m1 0bit d 0us m2 3072Kbit
Sent 83510091 bytes 1029278 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
period 1029159 work 83510091 bytes rtwork 82189624 bytes level 0


tc -s filter show dev
filter parent 1: protocol ip pref 1 fw
filter parent 1: protocol ip pref 1 fw handle 0x1 classid 1:11

iptables -t mangle -L voip -v -x
Chain voip (1 references)
pkts bytes target prot opt in out source destination
0 0 MARK udp -- any any anywhere anywhere udp spt:sip MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp dpt:sip MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp spt:iax MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp dpt:iax MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp spts:10000:20000 MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp dpts:10000:20000 MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp spt:sip-tls MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere anywhere udp dpt:sip-tls MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any x.x.x.18 anywhere MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere x.x.x.18 MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any x.x.x.24 anywhere MARK xset 0x1/0xffffffff
0 0 MARK udp -- any any anywhere x.x.x.24 MARK xset 0x1/0xffffffff

Bandwidth Shaping with Linux

On the router, the device, br0 is the bridged device that is in the internet side of things. We will use that device for shaping our internet traffic in and out of the router. I am using my home internet connection, which is Cox cable internet with 12Mbps download and 2Mbps upload or 12288 kilobits per second and 2048 kilobits per second, respectively.
First, lets setup some bash variables to point to the various commands we will use throughout the script. We will also set variables to indicate our maximum bandwidth in both directions.

TC="/usr/sbin/tc"
IPT="/usr/sbin/iptables"
IP="/usr/sbin/ip"
INSMOD="/sbin/insmod"
RMMOD="/sbin/rmmod"
DNLD_BANDWIDTH="12288kbit"
UPLD_BANDWIDTH="2048kbit"
Next, lets setup the download shaping by adding a queuing discipline (qdisc) to device br0 and tell the qdisc the maximum throughput.
TCA="${TC} class add dev br0"
TFA="${TC} filter add dev br0"
TQA="${TC} qdisc add dev br0"
${TQA} root handle 1: htb
${TCA} parent 1: classid 1:1 htb rate ${DNLD_BANDWIDTH}
Next, we are going to setup 2 classes. Each class will be setup with a guaranteed bandwidth and a maximum bandwidth if the other class is underutilized. The first class will have a guaranteed download bandwidth of 8Mbps. The second class will have a guaranteed download bandwidth of 4Mbps. Both classes will be able to utilize up to 12Mbps depending on how active the other class is.
{TCA} parent 1:1 classid 1:10 htb rate 8192kbit ceil ${DNLD_BANDWIDTH} prio 1
{TCA} parent 1:1 classid 1:11 htb rate 4096kbit ceil ${DNLD_BANDWIDTH} prio 2
{TQA} parent 1:10 handle 10: sfq perturb 10
{TQA} parent 1:11 handle 11: sfq perturb 10
Now we need to setup a filter for each class. This is ensure only packets marked with the filter’s tag will be restricted. The mark is denoted by the ip handle. Here we will use 10 and 11, to match the classids of the classes we just defined.
${TFA} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFA} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
Now to setup the upload shaping, we have to create a imq device.
${INSMOD} imq
${INSMOD} ipt_IMQ
${IP} link set imq0 up
Next, we need to setup a qdisc, classes, and filters for our 2 classes. Just like we did for download, only this time using the imq0 device and the upload bandwidths. The first class will have a guaranteed upload bandwidth of ~1.3Mbps and the second class will have a guaranteed upload bandwidth of 700Kbps.
TCAU="${TC} class add dev imq0"
TFAU="${TC} filter add dev imq0"
TQAU="${TC} qdisc add dev imq0"
${TQAU} root handle 1: htb
${TCAU} parent 1: classid 1:1 htb rate ${UPLD_BANDWIDTH}
${TCAU} parent 1:1 classid 1:10 htb rate 1348kbit ceil ${UPLD_BANDWIDTH} prio 1
${TCAU} parent 1:1 classid 1:11 htb rate 700kbit ceil ${UPLD_BANDWIDTH} prio 2
${TQAU} parent 1:10 handle 10: sfq perturb 10
${TQAU} parent 1:11 handle 11: sfq perturb 10
${TFAU} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFAU} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
Finally, now that all our shaping is setup, we need to use iptables to mark packets to indicate which packets to shape. My internal network is 192.168.1.0/24. So we only mark packets headed for the internet and leave internal traffic alone. The first class will be restricted to a single IP address. The second class will be restrict to a group of IPs using CIDR notation (32 DHCP addresses from the router).
# download
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.2 -j MARK --set-mark 10
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.128/27 -j MARK --set-mark 11
# upload
${IPT} -t mangle -A PREROUTING -j IMQ --todev 0
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.2 -j MARK --set-mark 10
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.128/27 -j MARK --set-mark 11
Note: I would really like to use iptables range of address notation (e.g. -m iprange –src-range 192.168.1.3-192.168.1.254), but current builds of DD-WRT do not seem to work with that notation. I posted to the DD-WRT forums and I’ll I got was IP ranges are not supported. So for my own purposes, I just have giant script with many iptables commands, one for each IP address I want to shape.
To make it easy to start, stop, restart, I wrote an init.d style script for the above. I use it as part of the DD-WRT custom firewall script.

#!/bin/bash
TC="/usr/sbin/tc"
IPT="/usr/sbin/iptables"
IP="/usr/sbin/ip"
INSMOD="/sbin/insmod"
RMMOD="/sbin/rmmod"
DNLD_BANDWIDTH="12228kbit"
UPLD_BANDWIDTH="2048kbit"
DNLD_CLASS10_BANDWIDTH="8192kbit"
DNLD_CLASS11_BANDWIDTH="4096kbit"
UPLD_CLASS10_BANDWIDTH="1348kbit"
UPLD_CLASS11_BANDWIDTH="700kbit"
[ -x ${TC} ] || exit 1
[ -x ${IPT} ] || exit 1
[ -x ${IP} ] || exit 1
[ -x ${INSMOD} ] || exit 1
[ -x ${RMMOD} ] || exit 1
case "${1}" in
    start)
        echo -n "Starting bandwidth shaping service ... "
        # download
        TCA="${TC} class add dev br0"
        TFA="${TC} filter add dev br0"
        TQA="${TC} qdisc add dev br0"
        ${TQA} root handle 1: htb
        ${TCA} parent 1: classid 1:1 htb rate ${DNLD_BANDWIDTH}
        ${TCA} parent 1:1 classid 1:10 htb rate ${DNLD_CLASS10_BANDWIDTH} ceil ${DNLD_BANDWIDTH} prio 1
        ${TCA} parent 1:1 classid 1:11 htb rate ${DNLD_CLASS11_BANDWIDTH} ceil ${DNLD_BANDWIDTH} prio 2
        ${TQA} parent 1:10 handle 10: sfq perturb 10
        ${TQA} parent 1:11 handle 11: sfq perturb 10
        ${TFA} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
        ${TFA} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
        # upload
        ${INSMOD} imq
        ${INSMOD} ipt_IMQ
        ${IP} link set imq0 up
        TCAU="${TC} class add dev imq0"
        TFAU="${TC} filter add dev imq0"
        TQAU="${TC} qdisc add dev imq0"
        ${TQAU} root handle 1: htb
        ${TCAU} parent 1: classid 1:1 htb rate ${UPLD_BANDWIDTH}
        ${TCAU} parent 1:1 classid 1:10 htb rate ${UPLD_CLASS10_BANDWIDTH} ceil ${UPLD_BANDWIDTH} prio 1
        ${TCAU} parent 1:1 classid 1:11 htb rate ${UPLD_CLASS11_BANDWIDTH} ceil ${UPLD_BANDWIDTH} prio 2
        ${TQAU} parent 1:10 handle 10: sfq perturb 10
        ${TQAU} parent 1:11 handle 11: sfq perturb 10
        ${TFAU} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
        ${TFAU} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
        # download
        ${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.2 -j MARK --set-mark 10
        ${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.128/27 -j MARK --set-mark 11
        # upload
        ${IPT} -t mangle -A PREROUTING -j IMQ --todev 0
        ${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.2 -j MARK --set-mark 10
        ${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.128/27 -j MARK --set-mark 11
        echo "done"
    ;;
    stop)
        echo -n "Stopping bandwidth shaping service ... "
        # download
        ${IPT} -t mangle -D POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.2 -j MARK --set-mark 10
        ${IPT} -t mangle -D POSTROUTING -s ! 192.168.1.0/24 -d 192.168.1.128/27 -j MARK --set-mark 11
        # upload
        ${IPT} -t mangle -D PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.2 -j MARK --set-mark 10
        ${IPT} -t mangle -D PREROUTING -d ! 192.168.1.0/24 -s 192.168.1.128/27 -j MARK --set-mark 11
        ${IPT} -t mangle -D PREROUTING -j IMQ --todev 0
        ${TC} qdisc del dev br0 root
        ${TC} qdisc del dev imq0 root
        ${IP} link set imq0 down
        ${RMMOD} ipt_IMQ
        ${RMMOD} imq
        echo "done"
    ;;
    restart)
        ${0} stop
        sleep 1
        ${0} start
    ;;
    status)
        ${TC} qdisc show dev br0
        ${TC} class show dev br0
        ${TC} filter show dev br0
        ${TC} qdisc show dev imq0
        ${TC} class show dev imq0
        ${TC} filter show dev imq0
    ;;
    *)
        echo "Usage: ${0} {start|stop|restart|status}"
        exit 1
    ;;
esac
exit 0
http://roback.cc/wp/2009/09/bandwidth-shaping-with-linux/#Introduction

Traffic shaping with tc

Sometimes it's necessary to limit traffic bandwidth from and to a container. You can do it using ordinary tc tool.

Contents

[hide]

[edit] Packet routes

First of all, a few words about how packets travel from and to a container. Suppose we have Hardware Node (HN) with a container (CT) on it, and this container talks to some Remote Host (RH). HN has one "real" network interface eth0 and, thanks to OpenVZ, there is also "virtual" network interface venet0. Inside the container we have interface venet0:0.
venet0:0               venet0    eth0
CT >------------->-------------> HN >--------->--------> RH

    venet0:0               venet0    eth0
CT <-------------<-------------< HN <---------<--------< RH

[edit] Limiting outgoing bandwidth

We can limit container outgoing bandwidth by setting the tc filter on eth0.
DEV=eth0
tc qdisc del dev $DEV root
tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 100mbit
tc class add dev $DEV parent 1: classid 1:1 cbq rate 256kbit allot 1500 prio 5 bounded isolated
tc filter add dev $DEV parent 1: protocol ip prio 16 u32 match ip src X.X.X.X flowid 1:1
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
X.X.X.X is an IP address of container.

[edit] Limiting incoming bandwidth

This can be done by setting the tc filter on venet0:
DEV=venet0
tc qdisc del dev $DEV root
tc qdisc add dev $DEV root handle 1: cbq avpkt 1000 bandwidth 100mbit
tc class add dev $DEV parent 1: classid 1:1 cbq rate 256kbit allot 1500 prio 5 bounded isolated
tc filter add dev $DEV parent 1: protocol ip prio 16 u32 match ip dst X.X.X.X flowid 1:1
tc qdisc add dev $DEV parent 1:1 sfq perturb 10
Note that X.X.X.X is an IP address of container.

[edit] Limiting CT to HN talks

As you can see, two filters above don't limit container to HN talks. I mean a container can emit as much traffic as it wishes. To make such a limitation from the HN, it is necessary to use tc police on venet0:
DEV=venet0
tc filter add dev $DEV parent 1: protocol ip prio 20 u32 match u32 1 0x0000 police rate 2kbit buffer 10k drop flowid :1

[edit] Limiting packets per second rate from container

To prevent dos atacks from the container you can limit packets per second rate using iptables.
DEV=eth0
iptables -I FORWARD 1 -o $DEV -s X.X.X.X -m limit --limit 200/sec -j ACCEPT
iptables -I FORWARD 2 -o $DEV -s X.X.X.X -j DROP
Here X.X.X.X is an IP address of container.

[edit] An alternate approch using HTB

For details refer to the HTB Home Page
#!/bin/sh
#
# Incoming traffic control
#
CT_IP1=$1
CT_IP2=$2
DEV=venet0
#
tc qdisc del dev $DEV root
#
tc qdisc add dev $DEV root handle 1: htb default 10
#
tc class add dev $DEV parent 1: classid 1:1 htb rate 100mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:10 htb rate 10mbit ceil 10mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:20 htb rate 20mbit ceil 20mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:30 htb rate 30mbit ceil 30mbit burst 15k
#
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10
#
if [ ! -z $CT_IP1 ]; then
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dst "$CT_IP1" flowid 1:20 
fi
if [ ! -z $CT_IP2 ]; then
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip dst "$CT_IP2" flowid 1:30 
fi
#
echo;echo "tc configuration for $DEV:"
tc qdisc show dev $DEV
tc class show dev $DEV
tc filter show dev $DEV
#
# Outgoing traffic control
#
DEV=eth0
#
tc qdisc del dev $DEV root
#
tc qdisc add dev $DEV root handle 1: htb default 10
#
tc class add dev $DEV parent 1: classid 1:1 htb rate 100mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:10 htb rate 10mbit ceil 10mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:20 htb rate 20mbit ceil 20mbit burst 15k
tc class add dev $DEV parent 1:1 classid 1:30 htb rate 30mbit ceil 30mbit burst 15k
#
tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $DEV parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev $DEV parent 1:30 handle 30: sfq perturb 10
#
if [ ! -z $CT_IP1 ]; then
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip src "$CT_IP1" flowid 1:20
fi
if [ ! -z $CT_IP2 ]; then
    tc filter add dev $DEV protocol ip parent 1:0 prio 1 u32 match ip src "$CT_IP2" flowid 1:30
fi
#
echo;echo "tc configuration for $DEV:"
tc qdisc show dev $DEV
tc class show dev $DEV
tc filter show dev $DEV
 
http://wiki.openvz.org/Traffic_shaping_with_tc 

HIERARCHICAL FAIR SERVICE CURVE

HIERARCHICAL FAIR SERVICE CURVE
 

HISTORY & INTRODUCTION

HFSC - Hierarchical Fair Service Curve was first presented at SIGCOMM'97. Developed as a part of ALTQ (ALTernative Queuing) on NetBSD, found its way quickly to other BSD systems, and then a few years ago became part of the linux kernel. Still, it's not the most popular scheduling algorithm - especially if compared to HTB - and it's not well documented from enduser's perspective. This introduction aims to explain how HFSC works without going to deep into math side of things (although some if it will be inevitable). In short HFSC aims to:

1)
guarantee precise bandwidth and delay allocation for all leaf classes (realtime criterion)
2)
allocate excess bandwidth fairly as specified by class hierarchy (linkshare & upperlimit criterion)
3)
minimize any discrepancy between the service curve and the actual amount of service provided during linksharing
The main "selling" point of HFSC is feature (1), which is achieved by using nonlinear service curves (more about what it actually is later). This is particularly useful in VoIP or games, where not only guarantee of consistent bandwidth is important, but initial delay of a data stream as well. Note that it matters only for leaf classes (where the actual queues are) - thus class hierarchy is ignored in realtime case.
Feature (2) is well, obvious - any algorithm featuring class hierarchy (such as HTB or CBQ) strives to achieve that. HFSC does that well, although you might end with unusual situations, if you define service curves carelessly - see section CORNER CASES for examples.
Feature (3) is mentioned due to the nature of the problem. There may be situations where it's either not possible to guarantee service of all curves at the same time, and/or it's impossible to do so fairly. Both will be explained later. Note that this is mainly related to interior (aka aggregate) classes, as the leafs are already handled by (1). Still - it's perfectly possible to create a leaf class w/o realtime service, and in such case - the caveats will naturally extend to leaf classes as well.
 

Bandwidth Limiting with IP Masquerade

Bandwidth Limiting with IP Masquerade - Howto


Contents
  Introduction
  Requirements
  Setting Bandwidth
  Marking Packets for Limiting
  Bandwidth Monitoring
  Conclusion

Introduction

This document is meant for IP Masquerade users who want to limit specific host's bandwidth.
The example made throughout the document is a aDSL line (640Kbits download / 160Kbits  upload) where
the DHCP hosts of the subnet are bandwidth limited and also forced through a cachine proxy.

My router specs are as follows:

Distribution:
Debian 2.2 (stable)
Technically, its Debian 3.0 (unstable), buy only the sysinit scripts, bind, sendmail, dhcp, nfs, samba and X are kept at the bleeding edge. (All the major 'Services').
Hardware:
CPU: 466Mhz Celeron
RAM: 192MB
DISK: 40GB 7200 RPM Maxtor ATA100, 2GB IBM 5400 RPM ATA33

Services:
DHCP Server
DNS Server
Mail Server
IP Masquerade (port fowarding also)
Caching Proxy (Squid)
Samba server
NFS Server

Requirements

The requirements here will only pertain to setting up bandwidth limiting and NOT IP Masquerading, DHCP Server, NFS Server, etc.

Kernel Requirements:

All IPTABLES support needed for IP Masquerade plus
  CONFIG_IP_NF_CONNTRACK
  CONFIG_IP_NF_TARGET_MARK --> This is for marking packets. We are going to mark the packets we want limited with this

QoS and/or fair queueing
  CONFIG_NET_SCH_CBQ
  CONFIG_NET_CLS_FW

Now I usually compile all the IPTABLES and QoS and/or fair queueing stuff as modules, but lsmod only shows those above as in use.

Software Requirements:

IPTABLES --> http://www.iptables.org/
iproute2   --> ftp://ftp.inr.ac.ru/ip-routing/  --> Most distributions come with this defaultly installed

Setting Bandwidth

I set my bandwidth in a shell script for the purpose of having it set on boot time and for ease and stopping and starting.
#!/bin/bash
#
#  All Rates are in Kbits, so in order to gets Bytes divide by 8
#  e.g. 25Kbps == 3.125KB/s
#
TC=/sbin/tc
DNLD=150Kbit              # DOWNLOAD Limit
DWEIGHT=15Kbit         # DOWNLOAD Weight Factor ~ 1/10 of DOWNLOAD Limit
UPLD=25KBit                # UPLOAD Limit
UWEIGHT=2Kbit           # UPLOAD Weight Factor

tc_start() {

    $TC qdisc add dev eth0 root handle 11: cbq bandwidth 100Mbit avpkt 1000 mpu 64
    $TC class add dev eth0 parent 11:0 classid 11:1 cbq rate $DNLD weight $DWEIGHT allot 1514 prio 1 avpkt 1000 bounded
    $TC filter add dev eth0 parent 11:0 protocol ip handle 4 fw flowid 11:1

    $TC qdisc add dev eth1 root handle 10: cbq bandwidth 10Mbit avpkt 1000 mpu 64
    $TC class add dev eth1 parent 10:0 classid 10:1 cbq rate $UPLD weight $UWEIGHT allot 1514 prio 1 avpkt 1000 bounded
    $TC filter add dev eth1 parent 10:0 protocol ip handle 3 fw flowid 10:1

}

tc_stop() {

    $TC qdisc del dev eth0 root
    $TC qdisc del dev eth1 root

}

tc_restart() {

    tc_stop
    sleep 1
    tc_start

}

tc_show() {

    echo ""
    echo "eth0:"
    $TC qdisc show dev eth0
    $TC class show dev eth0
    $TC filter show dev eth0
    echo ""

    echo "eth1:"
    $TC qdisc show dev eth1
    $TC class show dev eth1
    $TC filter show dev eth1
    echo ""

}

case "$1" in

  start)

    echo -n "Starting bandwidth shaping: "
    tc_start
    echo "done"
    ;;

  stop)

    echo -n "Stopping bandwidth shaping: "
    tc_stop
    echo "done"
    ;;

  restart)

    echo -n "Restarting bandwidth shaping: "
    tc_restart
    echo "done"
    ;;

  show)
   
    tc_show()
    ;;

  *)

    echo "Usage: /etc/init.d/tc.sh {start|stop|restart|show}"
    ;;

esac

exit 0

Now lets go through that.
At the top are some variables which make it easier to change the entire script with on change.
THIS SCRIPT IS ONLY ** ONE ** RULESET.
You can add as many rules as you like. I don't run a ISP, I only needed to restrict a few people.

This scripts assumes 2 things.
eth0 ==> is local network e.g. 192.168.0.0/24
eth1 ==> is Internet network e.g. Your ISP

Stop, Restart, and Show are self explanitory. I will not explain them.

Start:
$TC qdisc add dev eth0 root handle 11: cbq bandwidth 100Mbit avpkt 1000 mpu 64
$TC class add dev eth0 parent 11:0 classid 11:1 cbq rate $DNLD weight $DWEIGHT allot 1514 prio 1 avpkt 1000 bounded
$TC filter add dev eth0 parent 11:0 protocol ip handle 4 fw flowid 11:1

$TC qdisc add dev eth1 root handle 10: cbq bandwidth 10Mbit avpkt 1000 mpu 64
$TC class add dev eth1 parent 10:0 classid 10:1 cbq rate $UPLD weight $UWEIGHT allot 1514 prio 1 avpkt 1000 bounded
$TC filter add dev eth1 parent 10:0 protocol ip handle 3 fw flowid 10:1

First the top 3 three lines are for the Download bandwidth.

The first line creates and "PARENT" qdisc:
  --> $TC qdisc add dev eth0 root handle 11: cbq bandwidth 100Mbit avpkt 1000 mpu 64
man tc for more information, but basically its the device definition. 100Mbit Netgear card.
Next line creates the child qdisc with will have the actual download limit in it.
  --> $TC class add dev eth0 parent 11:0 classid 11:1 cbq rate $DNLD weight $DWEIGHT allot 1514 prio 1 avpkt 1000 bounded
man tc and friends again if you need any more definition than that. Personally I don't know what all it means or any optimal settings.
I just used the suggested man page defaults.
The last line and VERY important line, sets the handle on the child qdisc.
It sets the handle to 4.  Later we will use iptables to MARK the download packets with a 4 mark, and thats how the child qdisc will know
which packets to limit and which to let alone.

The Bottom three lines are for the uploading bandwidth.
Its the same as the download, but the device has changed from eth0 to eth1, the variables have changed from $DNLD to UPLD etc, and
the handle has changed from 4 to 3.

Marking Packets for Limiting

Ok now you are ready to mark packets as they come through in order to limit them.
I just added the next few lines to my rc.firewall.

# Mark packets to route
# Upload marking
$IPTABLES -t mangle -A FORWARD -s 192.168.0.128/29 -j MARK --set-mark 3
$IPTABLES -t mangle -A FORWARD -s 192.168.0.6 -j MARK --set-mark 3

# Download marking
$IPTABLES -t mangle -A POSTROUTING -s ! 192.168.0.0/24 -d 192.168.0.128/29 -j MARK --set-mark 4
$IPTABLES -t mangle -A POSTROUTING -s ! 192.168.0.0/24 -d 192.168.0.6 -j MARK --set-mark 4

Here I mark the following hosts:
192.168.0.6
192.168.0.128/29 =>
        192.168.0.128
        192.168.0.129
        192.168.0.130
        192.168.0.131
        192.168.0.132
        192.168.0.133
        192.168.0.134
        192.168.0.135

I hope no one needs help with Subnet masks. :)
Downloads are marked 4 and uploads are marked 3

29 means
http://szabilinux.hu/bandwidth/index.html

TC STAB

NAME

tc-stab - Generic size table manipulations  

SYNOPSIS

tc qdisc add ... stab \
[ mtu BYTES ] [ tsize SLOTS ] \ [ mpu BYTES ] [ overhead BYTES ] [ linklayer TYPE ] ...
TYPE := adsl | atm | ethernet
For the description of BYTES - please refer to the UNITS section of tc(8).

mtu
maximum packet size we create size table for, assumed 2048 if not specified explicitly
tsize
required table size, assumed 512 if not specified explicitly
mpu
minimum packet size used in computations
overhead
per-packet size overhead (can be negative) used in computations
linklayer
required linklayer adaptation.
 

DESCRIPTION

Size tables allow manipulation of packet size, as seen by whole scheduler framework (of course, the actual packet size remains the same). Adjusted packet size is calculated only once - when a qdisc enqueues the packet. Initial root enqueue initializes it to the real packet's size. Each qdisc can use different size table, but the adjusted size is stored in area shared by whole qdisc hierarchy attached to the interface (technically, it's stored in skb). The effect is, that if you have such setup, the last qdisc with a stab in a chain "wins". For example, consider HFSC with simple pfifo attached to one of its leaf classes. If that pfifo qdisc has stab defined, it will override lengths calculated during HFSC's enqueue, and in turn, whenever HFSC tries to dequeue a packet, it will use potentially invalid size in its calculations. Normal setups will usually include stab defined only on root qdisc, but further overriding gives extra flexibility for less usual setups.
Initial size table is calculated by tc tool using mtu and tsize parameters. The algorithm sets each slot's size to the smallest power of 2 value, so the whole mtu is covered by the size table. Neither tsize, nor mtu have to be power of 2 value, so the size table will usually support more than is required by mtu.
For example, with mtu~=~1500 and tsize~=~128, a table with 128 slots will be created, where slot 0 will correspond to sizes 0-16, slot 1 to 17~-~32, ..., slot 127 to 2033~-~2048. Note, that the sizes are shifted 1 byte (normally you would expect 0~-~15, 16~-~31, ..., 2032~-~2047). Sizes assigned to each slot depend on linklayer parameter.
Stab calculation is also safe for an unusual case, when a size assigned to a slot would be larger than 2^16-1 (you will lose the accuracy though).
During kernel part of packet size adjustment, overhead will be added to original size, and after subtracting 1 (to land in the proper slot - see above about shifting by 1 byte) slot will be calculated. If the size would cause overflow, more than 1 slot will be used to get the final size. It of course will affect accuracy, but it's only a guard against unusual situations.
Currently there're two methods of creating values stored in the size table - ethernet and atm (adsl):

ethernet
This is basically 1-1 mapping, so following our example from above (disregarding mpu for a moment) slot 0 would have 8, slot 1 would have 16 and so on, up to slot 127 with 2048. Note, that mpu~>~0 must be specified, and slots that would get less than specified by mpu, will get mpu instead. If you don't specify mpu, the size table will not be created at all, although any overhead value will be respected during calculations.
atm, adsl
ATM linklayer consists of 53 byte cells, where each of them provides 48 bytes for payload. Also all the cells must be fully utilized, thus the last one is padded if/as necessary. When size table is calculated, adjusted size that fits properly into lowest amount of cells is assigned to a slot. For example, a 100 byte long packet requires three 48-byte payloads, so the final size would require 3 ATM cells - 159 bytes. For ATM size tables, 16~bytes sized slots are perfectly enough. The default values of mtu and tsize create 4~bytes sized slots.
 

TYPICAL OVERHEADS

The following values are typical for different adsl scenarios (based on [1] and [2]):
LLC based:
PPPoA - 14 (PPP - 2, ATM - 12) PPPoE - 40+ (PPPoE - 8, ATM - 18, ethernet 14, possibly FCS - 4+padding) Bridged - 32 (ATM - 18, ethernet 14, possibly FCS - 4+padding) IPoA - 16 (ATM - 16)
VC Mux based:
PPPoA - 10 (PPP - 2, ATM - 8) PPPoE - 32+ (PPPoE - 8, ATM - 10, ethernet 14, possibly FCS - 4+padding) Bridged - 24+ (ATM - 10, ethernet 14, possibly FCS - 4+padding
IPoA - 8 (ATM - 8)

There're few important things regarding the above overheads:
*
IPoA in LLC case requires SNAP, instead of LLC-NLPID (see rfc2684) - this is the reason, why it actually takes more space than PPPoA.
*
In rare cases, FCS might be preserved on protocols that include ethernet frame (Bridged and PPPoE). In such situation, any ethernet specific padding guaranteeing 64 bytes long frame size has to be included as well (see rfc2684). In the other words, it also guarantees that any packet you send will take minimum 2 atm cells. You should set mpu accordingly for that.
*
When size table is consulted, and you're shaping traffic for the sake of another modem/router, ethernet header (without padding) will already be added to initial packet's length. You should compensate for that by subtracting 14 from the above overheads in such case. If you're shaping directly on the router (for example, with speedtouch usb modem) using ppp daemon, layer2 header will not be added yet. For more thorough explanations, please see [1] and [2]. http://www.linuxhowtos.org/manpages/8/tc-stab.htm

Sunday, March 27, 2011

Optimization of TCP/IP Traffic Across Shared ADSL

This thesis presents practical studies of the TCP performance problems caused by the asymmetric nature of ADSL connections. Previously, it has been shown on other types of asymmetric links that TCP throughput may be reduced due to a variable and imperfect ACK feedback. The upstream capacity of ADSL products in general does not disturb the ACK feedback mechanism, but we analyze and document that TCP traffic across ADSL in fact is affected by the asymmetric nature of ADSL, when utilizing the upstream capacity. For a single user ADSL installation it is manageable to avoid upstream congestion, but for larger networks, connected to the Internet by ADSL, the rise of peer-to-peer file sharing applications may result in a permanently congested upstream link.
The thesis provides evidence that the achievable downstream throughput is reduced significantly in case of a saturated upstream link. Saturation of the upstream link introduces a high queueing delay that effectively renders the connection useless for interactive and other delay-sensitive applications (like VoIP).
Previous work within the field of asymmetry has primarily been concerned with optimizing downstream throughput. Our solution incorporates latency as an important design parameter in order to support different types of network applications at the same time. The thesis also provides a practical solution to mitigate these problems. We demonstrate how it is possible to achieve full downstream and upstream utilization, while at the same time supporting different delay-sensitive applications, using the packet scheduler of a Linux based middlebox between the network and the ADSL connection.
On ADSL the available bandwidth for IP traffic varies significantly, which is caused by protocol overhead and packet/cell aligning at the ATM/AAL5 link layer. Depending on packet sizes the available bandwidth can be reduced up to 62 percentage. Therefore, a packet scheduler needs to account for the varying available bandwidth by accounting for the link layer overhead. As part of implementing a practical solution, based on Linux, the Linux Traffic Control system have been modified to perform accurate packet scheduling through modeling the ATM link layer overhead of ADSL.

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