Previous page: Subnet/Seperate Page
Next page: My Computers

Traffic Shaping

Ipcop 1.4 comes with traffic shaping built in, but it is really geared (it seems) to providing priority to certain classses of traffic. I wanted to have an element of this, but also to ensure that my client pc's and my linux servers had a fair share of the bandwidth.  It didnt happen often, but it was infuriating when it did; to have slow browsing or downloading because someone else was downloading a large file.

There are loads of resources about traffic shaping on the internet, and one thing became apparent - it is not an exact science!  I read and read, and tried and tried..... My solution was one based on the coyote Linux qos script.  It works nicely here, not an exact split in download bandwidth (not sure why, but it seems the XP machine always gains more bandwidth than the 98 one)

The scripts I use are (rc.qos, rc.qos.status, and rc.qos.stop - and they detailed below).  I store them in /etc/rc.d and call the rc.qos script as part on my /etc/rc.d/rc.firewall.local start.

To help you understand it, I offer the following notes:

This runs on ipcop 1.4 with the standard traffic shaping is off, and this script is run from a command line or as above

192.168.0.192/27 are my servers.

192.168.0.224/27 are my Routers etc.

192.168.0.160/27 are my Hi Priority Client PCs

192.168.0.128/27 are my medium Priority PCs

192.168.0.0/25 are dhcp, visiting, low priority PCs

eth0 is green (LAN) and eth1 is red (ethernet to ADSL modem)

The major classes (1:10,11,12) are split into minor classes (ie 1:100,101,102) to allow fairness within a single clients operation.

192.168.0.1/24 is green, 192.168.4.1/24 is orange. These have a higher upstream output (class 1:2) of eth0 because they are not related to red downloads.

Shaping can only be applied to upstream traffic.  This script applies upstream filtering to both red and green, where the green shaping is treated as if it was red downstream. This script does not work with the squid proxy on.  This is because it relies on marking packets and if these go through a proxy, the marking is lost.

  1. rc.qos
    #!/bin/sh
    #
    # ipcop 1.4.x Traffic Shaping
    #
    # execute script from command line
    # distributed under GPL License
    # author: Allan Kissack 2005
    #
    # Based on Coyote QOS init scripts
    #
    IF_LOCAL=eth0
    IF_INET=eth1
    IF_DMZ=eth2
    #FULLDOWN=2048kbit
    #FULLUP=256kbit
    #HIDOWN=2036kbit
    #HIUP=200kbit
    #HIDRATE=509kbit
    #HIURATE=50kbit
    #MIDDOWN=1100kbit
    #MIDUP=150kbit
    #MIDDRATE=256kbit
    #MIDURATE=40kbit
    #LOWDOWN=900kbit
    #LOWUP=90kbit
    #LOWDRATE=200kbit
    #LOWURATE=20kbit
    #SLOWDOWN=750kbit
    #SLOWUP=45kbit
    #SLOWDRATE=100kbit
    FULLDOWN=6500kbit
    FULLUP=448kbit
    HIDOWN=5000kbit
    HIUP=400kbit
    HIDRATE=509kbit
    HIURATE=54kbit
    MIDDOWN=3000kbit
    MIDUP=270kbit
    MIDDRATE=256kbit
    MIDURATE=40kbit
    LOWDOWN=2000kbit
    LOWUP=180kbit
    LOWDRATE=200kbit
    LOWURATE=20kbit
    SLOWDOWN=400kbit
    SLOWUP=20kbit
    SLOWDRATE=50kbit
    SLOWURATE=3kbit
    LANSPEED=100mbit
    #
    echo "* Deleting old QOS classes and root filters"
    /sbin/tc qdisc del dev $IF_LOCAL root 2>/dev/null
    /sbin/tc qdisc del dev $IF_INET root 2>/dev/null
    /sbin/tc qdisc del dev $IF_DMZ root 2>/dev/null
    # echo "* Deleting old root filters..."
    /sbin/tc filter del dev $IF_LOCAL parent 1:2 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_LOCAL parent 1:1 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_LOCAL parent 1: pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:1 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1: pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_DMZ parent 1:2 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_DMZ parent 1:1 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_DMZ parent 1: pref 100 2>/dev/null
    echo "* Initializing Traffic control"
    /sbin/tc qdisc add dev $IF_LOCAL root handle 1: htb default 90 r2q 1
    /sbin/tc class add dev $IF_LOCAL parent 1: classid 1:1 htb rate $FULLDOWN burst 16k
    /sbin/tc class add dev $IF_LOCAL parent 1: classid 1:2 htb rate $LANSPEED burst 16k
    /sbin/tc qdisc add dev $IF_INET root handle 1: htb default 89 r2q 1
    /sbin/tc class add dev $IF_INET parent 1:0 classid 1:1 htb rate $FULLUP burst 8k
    /sbin/tc qdisc add dev $IF_DMZ root handle 1: htb default 90 r2q 1
    /sbin/tc class add dev $IF_DMZ parent 1: classid 1:1 htb rate $FULLDOWN burst 16k
    /sbin/tc class add dev $IF_DMZ parent 1: classid 1:2 htb rate $LANSPEED burst 16k
    echo "* Initializing packet mangling..."
    /sbin/iptables -F PREROUTING -t mangle
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.0/24 -j MARK --set-mark 255
    echo "* Building Downstream/Upstream classes..."
    echo "* 1:10 = 192.168.0.224/27 (Routers)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:10 htb prio 1 rate $HIDRATE ceil $HIDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:10 htb prio 1 rate $HIURATE ceil $HIUP burst 8k
    /sbin/tc filter del dev $IF_LOCAL parent 1:10 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:10 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.0.224/27 flowid 1:10
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.224/27 -j MARK --set-mark 10
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 10 pref 100 fw classid 1:10
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:10 handle 10: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:10 handle 10: sfq perturb 10
    echo "* 1:20 = 192.168.0.192/27 (Servers)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:20 htb prio 1 rate $LOWDRATE ceil $MIDDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:20 htb prio 1 rate $LOWURATE ceil $MIDUP burst 8k
    #/sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:20 htb prio 1 rate $LOWDRATE ceil $MIDDOWN burst 16k
    #/sbin/tc class add dev $IF_INET parent 1:1 classid 1:20 htb prio 1 rate $LOWURATE ceil $MIDUP burst 8k
    #
    /sbin/tc filter del dev $IF_LOCAL parent 1:20 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:20 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.0.192/27 flowid 1:20
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.192/27 -j MARK --set-mark 20
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 20 pref 100 fw classid 1:20
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:20 handle 20: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:20 handle 20: sfq perturb 10
    echo "* 1:30 = 192.168.0.160/27 (Hi Priority)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:30 htb prio 1 rate $HIDRATE ceil $HIDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:30 htb prio 1 rate $HIURATE ceil $HIUP burst 8k
    /sbin/tc filter del dev $IF_LOCAL parent 1:30 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:30 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.0.160/27 flowid 1:30
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.160/27 -j MARK --set-mark 30
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 30 pref 100 fw classid 1:30
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:30 handle 30: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:30 handle 30: sfq perturb 10
    echo "* 1:40 = 192.168.0.128/27 (Lo Priority)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:40 htb prio 1 rate $MIDDRATE ceil $MIDDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:40 htb prio 1 rate $MIDURATE ceil $MIDUP burst 8k
    /sbin/tc filter del dev $IF_LOCAL parent 1:40 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:40 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.0.128/27 flowid 1:40
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.128/27 -j MARK --set-mark 40
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 40 pref 100 fw classid 1:40
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:40 handle 40: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:40 handle 40: sfq perturb 10
    echo "* 1:50 = 192.168.0.0/25 (Other)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:50 htb prio 1 rate $LOWDRATE ceil $LOWDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:50 htb prio 1 rate $LOWURATE ceil $LOWUP burst 8k
    /sbin/tc filter del dev $IF_LOCAL parent 1:50 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:50 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.0.0/25 flowid 1:50
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.0.0/25 -j MARK --set-mark 50
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 50 pref 100 fw classid 1:50
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:50 handle 50: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:50 handle 50: sfq perturb 10
    echo "* 1:60 = 192.168.4.1 (Orange -> Red)"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:60 htb prio 1 rate $MIDDRATE ceil $MIDDOWN burst 16k
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:60 htb prio 1 rate $MIDURATE ceil $MIDUP burst 8k
    /sbin/tc filter del dev $IF_LOCAL parent 1:60 pref 100 2>/dev/null
    /sbin/tc filter del dev $IF_INET parent 1:60 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.4.1 flowid 1:60
    /sbin/iptables -A PREROUTING -t mangle -s 192.168.4.1 -j MARK --set-mark 60
    /sbin/tc filter add dev $IF_INET parent 1: protocol ip handle 60 pref 100 fw classid 1:60
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:60 handle 60: sfq perturb 10
    /sbin/tc qdisc add dev $IF_INET parent 1:60 handle 60: sfq perturb 10
    echo "* DMZ 1:10 = 192.168.4.0/24 (Red/Green -> Orange)"
    /sbin/tc class add dev $IF_DMZ parent 1:1 classid 1:10 htb prio 1 rate 60kbit ceil 100kbit burst 16k
    /sbin/tc filter del dev $IF_DMZ parent 1:10 pref 100 2>/dev/null
    /sbin/tc filter add dev $IF_DMZ protocol ip parent 1:1 pref 100 u32 match ip dst 192.168.4.0/24 flowid 1:10
    echo " - downstream junk (default) class: 12kbps, ceil: $FULLDOWN, burst: 4k"
    /sbin/tc class add dev $IF_LOCAL parent 1:1 classid 1:90 htb prio 2 rate 12kbit ceil $FULLDOWN burst 4k
    /sbin/tc qdisc add dev $IF_LOCAL parent 1:90 handle 90: sfq perturb 10
    echo " - upstream junk (default) class: 12kbps, ceil: $FULLUP, burst: 2k"
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:90 htb prio 2 rate 12kbit ceil $FULLUP burst 2k
    /sbin/tc qdisc add dev $IF_INET parent 1:90 handle 90: sfq perturb 10
    echo " - direct fw->inet class: 25kbps, ceil: $FULLUP, burst: 4k"
    /sbin/tc class add dev $IF_INET parent 1:1 classid 1:89 htb prio 1 rate 25kbit ceil $FULLUP burst 4k
    /sbin/tc qdisc add dev $IF_INET parent 1:89 handle 89: sfq perturb 10
    /sbin/tc class add dev $IF_DMZ parent 1:1 classid 1:90 htb prio 2 rate 12kbit ceil $FULLDOWN burst 4k
    /sbin/tc qdisc add dev $IF_DMZ parent 1:90 handle 90: sfq perturb 10
    echo "* Building new root DOWNSTREAM/UPSTREAM filters ..."
    /sbin/tc filter add dev $IF_INET protocol ip parent 1: handle 255 pref 100 fw classid 1:90
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1: pref 100 u32 match ip src 192.168.0.0/16 flowid 1:2
    /sbin/tc filter add dev $IF_LOCAL protocol ip parent 1: pref 100 u32 match ip dst 192.168.0.0/16 flowid 1:1
    /sbin/tc filter add dev $IF_DMZ protocol ip parent 1: pref 100 u32 match ip src 192.168.0.0/16 flowid 1:2
    /sbin/tc filter add dev $IF_DMZ protocol ip parent 1: pref 100 u32 match ip dst 192.168.0.0/16 flowid 1:1
    echo "QOS: init complete"
  2. rc.qos.stop
    #!/bin/sh
    #
    echo "* Deleting old root filters..."
    /sbin/tc qdisc del dev eth0 root 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1:13 pref 100 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1:12 pref 100 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1:11 pref 100 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1:10 pref 100 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1:1 pref 100 2>/dev/null
    /sbin/tc filter del dev eth0 parent 1: pref 100 2>/dev/null
    /sbin/tc qdisc del dev eth1 root 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1:13 pref 100 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1:12 pref 100 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1:11 pref 100 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1:10 pref 100 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1:1 pref 100 2>/dev/null
    /sbin/tc filter del dev eth1 parent 1: pref 100 2>/dev/null
    echo "QOS: STOPPED"
  3. rc.qos.status
    #!/bin/sh
    #
    echo "Current Downstream traffic control classes (LAN - eth0)"
    echo " - - - - - - - - - - - - - - - - - - - - - - - -"
    /sbin/tc -s class show dev eth0
    echo " "
    echo "Current Upstream traffic control classes (WWW - eth1)"
    echo " - - - - - - - - - - - - - - - - - - - - - - - -"
    /sbin/tc -s class show dev eth1

That's it.


^Top
Previous page: Subnet/Seperate Page
Next page: My Computers