Vuurmuur gets traffic shaping

The last weeks I’ve been working on adding traffic shaping support to Vuurmuur. The work is largely done, only the GUI part is still missing. But using vuurmuur_script it is already usable in the current SVN trunk. I’ve written before about my shaping ideas here.

The support currently focuses on three different options:

1. Limiting bandwidth usage by rules.

Per rule a limit can be set for the maximum amount of bandwidth all traffic from this rule uses. Both directions of a connection have different limits. The in_max and out_max options can be added to existing rules for this. The syntax of the in_max and out_max is simple: out_max=15kbps means that traffic in the source to destination direction of a rule can at max use 15 kb/s.

2. Guaranteeing bandwidth to rules.

Again per rule a guaranteed minimum of available bandwidth can be configured. This way you can for example make sure your VoIP calls get enough. It’s important to not over commit the bandwidth. If you do that Vuurmuur will issue a warning but will still work because HTB, the used scheduler, accepts it as well. In this case the minimal bandwidth can not be guaranteed. To use this option add the in_min and out_min options. The syntax is the same as with in_max/out_max.

3. Prioritizing rules.

Like the first two options the priority can be set per rule. It’s a number where 1 is the highest prio. The default prio is 3. The syntax is prio=1. The lowest prio possible is 255.

For each interface, Vuurmuur needs to know the maximal bandwidth. Also, the shaping can be enabled and disabled on a per interface basis. Because shaping is attached to interfaces, rules using source and/or destination ‘any’ or ‘firewall(any)’ won’t be able to shape. Also, only outgoing shaping is supported, which is no problem in a gateway setup because then all traffic is outgoing on one of the interfaces, but on traffic from and to the firewall, this can be a limitation.

For example, to set the bandwidth in the interface ‘inet-nic’ which has a bandwidth of 3072kbit/512kbit, use the following vuurmuur_script commands:

vuurmuur_script -M -i inet-nic -V SHAPE -S Yes
vuurmuur_script -M -i inet-nic -V BW_IN -S 3
vuurmuur_script -M -i inet-nic -V BW_IN_UNIT -S mbit
vuurmuur_script -M -i inet-nic -V BW_OUT -S 512
vuurmuur_script -M -i inet-nic -V BW_OUT_UNIT -S kbit

Using vuurmuur_conf, it’s already possible to set the location of the tc binary. Look at ‘Vuurmuur Config -> General’.

An example of what a full rule using shaping can look like:

accept service ftp from local.lan to world.inet options prio=2, in_max=200kbps, out_max=15kbps

This example limits HTTP downloading to a speed of 200kb/s and uploading to 15kb/s.

The coming days and weeks I’ll finish the GUI support and release a test version.

Vuurmuur: first baby steps in traffic shaping

Quite a while ago a placed a poll on the Vuurmuur Wiki, asking for the most important feature Vuurmuur needs. It turns out most people want traffic shaping. Traffic shaping has been on my todo list for a long time, but i never really got into using it, let alone understand it enough to integrate it into a GUI. So the last couple of days i had some spare time, and i have been checking it out. So far i am distinguishing the following types of traffic shaping.

First there is simple priorization: my VoIP/Gaming traffic should have priority over people up- and downloading ISO images. This is quite simple, and could be done using setting the ToS and creating some rules for that. In Vuurmuur, setting ToS could for example be done in a service.

Second, there is some more advanced priorization, with soft limits. This could for example be used in a situation where you say VoIP/Gaming should have a guaranteed bandwith of 20kb/s, but if on VoIP is active or not using the full 20kb/s, other traffic is allowed to use the 20kb/s in addition to the other bandwidth. Most important here is to keep interactive traffic responsive.

Third, the hard limits. For example saying that p2p should never be able to use more than 40kb/s, no matter how many bandwidth you have available. This could also be useful for assigning speed limits to specific hosts, for example in hosting companies.

Fourth and last, there is some misc stuff for which shaping can be useful, like limiting the rate of SYN packets, giving smaller packets priority over larger, etc.

Okay, on to my baby steps:

$TC qdisc add dev $DEV root handle 1: htb default 30

This creates a htb root qdisc, which defaults to class 1:30.

$TC class add dev $DEV parent 1: classid 1:1 htb rate $MAX_PPP_UP

Here we create the class, where we define the max speed of this class to be MAX_PPP_UP.

$TC class add dev $DEV parent 1:1 classid 1:10 htb rate 100kbit ceil $MAX_PPP_UP burst 4k prio 1
$TC class add dev $DEV parent 1:1 classid 1:20 htb rate $MAX_PPP_UP_BULK burst 0k prio 2
$TC class add dev $DEV parent 1:1 classid 1:30 htb rate 200kbit burst 1k prio 3
$TC class add dev $DEV parent 1:1 classid 1:40 htb rate 100kbit burst 0k prio 4

Here we define the actual limits. The first rule gets 100kbit guaranteed, but as a ceiling of the maximum speed. It has the highest priority. The second class is for bulk uploading, and it is set to about 70% of the maximum upload speed. With this set, i can upload at about 40kb/s, and still have a ping of around 80-100ms, while setting this higher will cause it to go into the 200+ms levels very quickly. I’ve also disabled burst for this class, because i don’t want ping spikes. The other two have hard limits, and can be used to really rate limit some traffic.

Like stated above, unclassified traffic gets into the default class 1:30. To have some traffic go into another class, i’m using the iptables CLASSIFY target:

# icmp gets high prio
$IPTABLES -t mangle -A FORWARD -i eth0 -o ppp0 -p icmp -j CLASSIFY –set-class 1:10

# http data from dmz to wan is bulk
$IPTABLES -t mangle -A FORWARD -i eth1 -o ppp0 -p tcp –sport 80 -j CLASSIFY –set-class 1:20

I like the CLASSIFY iptables target over the tc filter rules because it enables me to use the netfilter connection tracking helpers. This way i could for example say:

$IPTABLES -t mangle -A FORWARD -i eth0 -o ppp0 -m helper –helper sip -j CLASSIFY –set-class 1:10

So this way all traffic related to the SIP VoIP connection (the RTP stream) gets into the highest priority class.

This is all egress shaping, the only shaping that works well, or so everyone says. Ingress shaping is not as easy, for a number of reasons. First, we have no real control over the rate of traffic being sent to us. Second, linux shaping is not as advanced for ingress shaping as it is for egress shaping. IMQ and later IFB have been invented to deal with this, but i have never looked at it yet.

However, in a gateway setup, egress shaping can do all we need. Traffic that comes in on my ppp0 interface, gets out on my eth1 interface. At this eth1 interface we can do egress shaping for incoming traffic coming in on ppp0.

This about sums up my first attempt at understanding and using traffic shaping. So far i think it works very well. The next big question will be how this can be integrated into Vuurmuur. If i get some ideas about this, i’ll post them here.

Oh yeah, if anyone is interested in participating in this process, i have setup a page on the wiki to help determine what we want and how we want to do it: here. Feel free to add to it, edit, etc.