TrafficShaping

From MLDonkey
Jump to: navigation, search

An effective way to limit the impact mldonkey has on your usual internet surfing/online gaming habits is to use the netfilter package found in the linux kernel 2.4.20 and above to control your outbound traffic. If setup correctly it should let mldonkey have most of the bandwidth when the computer is idle, but will automatically cut back to make room for more important tasks, such as surfing or playing online games. This is roughly described here for a single machine, if mldonkey is on a different machine it will get a bit more complicated.


Contents

First things first

The first thing to be sure of is that your kernel supports netfilter and HTB (Hierarchical Token Buckets). It's best (and most of the time necessary) to compile your own kernel, there are not many stock kernels out there that come with this support built-in by default, especially when you also want support for marking packets by UID - it's still marked as experimental.

In your kernel menuconfig, make sure the following options are checked:

Networking options  --->
              [[*]] Network packet filtering (replaces ipchains)
              IP: Netfilter Configuration  --->
                           [[*]] IP tables support (required for filtering/masq/NAT)
                           [[*]]   netfilter MARK match support
                           [[*]]   Owner match support (EXPERIMENTAL)
                           [[*]]   Packet filtering
                           [[*]]   Packet mangling
                           [[*]]     MARK target support
              QoS and/or fair queueing  --->
                            [[*]]   HTB packet scheduler
                            [[*]]     Traffic policing (needed for in/egress)

Make the kernel, boot, and check what's broken. The next things that need to be installed are iproute2 and iptables. These two packages should be in your distros favored package management system, if not you can get iproute2 at [1]] and iptables at [[2]. iptables is used to manipulate the mangling table of your kernel, and tc will do the actual bandwidth control.

The script

To start things off, here's a sample traffic control script:

#!/bin/sh -x
# be verbose!

tc qdisc add dev eth0 root handle 1: htb default 20
# add new htb handler on eth0, default for traffic is 20

tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit ceil 100mbit
# root class

tc class add dev eth0 parent 1:1 classid 1:10 htb rate 99mbit ceil 100mbit
# ethernet class 1:10

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 1mbit ceil 100mbit
# internet

tc class add dev eth0 parent 1:11 classid 1:20 htb rate 20kbps ceil 30kbps
# we use this class for the bulk traffic

tc class add dev eth0 parent 1:11 classid 1:21 htb rate 5kbps ceil 30kbps
# high priority internet traffic

tc class add dev eth0 parent 1:11 classid 1:22 htb rate 5kbps ceil 30kbps
# mldonkey's class

# The above commands set up the HTB queues where we will \"dump\" our packets in
# Now it's time to mark the packets:

iptables -A POSTROUTING -t mangle -o eth0 -p tcp -m length --length :64 -j MARK --set-mark 21
# high priority (small packets), used for ACKs  (allows regular transfers with no slowdown)

iptables -A POSTROUTING -t mangle -o eth0 -p tcp --dport 22 -j MARK --set-mark 21
iptables -A POSTROUTING -t mangle -o eth0 -p tcp --sport 22 -j MARK --set-mark 21
# SSH traffic  (port 22) - only use this if you have an ssh server running or ssh a lot

iptables -A OUTPUT -t mangle -o eth0 -m owner --uid-owner 1001 -j MARK --set-mark 22
# This marks all packages sent by user 1001, change this to the user  mldonkey is running under
# (there should ONLY mldonkey be running with this UID)

# at the end, mark all traffic that is for the local LAN to be put into 10
iptables -A POSTROUTING -t mangle -o eth0 -p tcp -d 192.168.1.0/24 -j MARK --set-mark 10

# flow handling (after marking)
tc filter add dev eth0 parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:21
tc filter add dev eth0 parent 1:0 prio 0 protocol ip handle 22 fw flowid 1:22
tc filter add dev eth0 parent 1:0 prio 0 protocol ip handle 10 fw flowid 1:10

Taking it apart

This shell script is what I use at home to control mldonkey, I strongly recommend you read it and that start writing your own from scratch. Now the dissection:

Classes and subclasses

The first section creates a new qdisc on eth0 (if you are on dial-up like DSL you might have to change that to ppp0). A root class named 1:1 is created after that and we will name all its children 1:x, starting with 1:10. Notice the \"default 20\": This means that all traffic on eth0, if not classified different, will go through 1:20.

Two subclasses are created, one for ethernet traffic (1:10) and one for internet traffic (1:11). The internet traffic class has three subclasses itself, 1:20, 1:21 and 1:22; for the \"normal\" internet traffic, for high priority, and for low priority stuff like mldonkey. Each of them gets assigned a rate and a ceil value. tc has a strange way to measuring traffic, mbit and kbit are what one would expect, Mbit and KBit, but to represent K (kilobyter per second) or M (megabytes per second), tc uses \"kbps\" or \"mbps\". The \"rate\" sets the minimum amount of bandwidth the class will get if all classes are running at (or over) maximum capacity. If there is extra capacity avaible because one class does not use up its bandwidth, its remaining bandwith will be redistributed to the other classes. The ceil value defines the maximum amount of network traffic a class can have at any given time, and for the internet classes it should be equal to the size of your internet connection (unless you want to put a hard limit on a certain class).

Iptables and marking

After the the queues are set up, iptables entries are made (the \"mangle\" table is used here) to mark the packets. A mark is a certain number that can be set \"on\" the packet, so it can be identified later. The beginning of the iptable commands is always the same: \"iptables -A POSTROUTING -t mangle -o eth0\". This means an entry is written to the POSTROUTING chain (or in one case the OUTPUT chain), on the device eth0. Then end is also always similiar, \"-j MARK\" means that the action to be taken upon a match is to mark, and \"--set-mark\" specifies which number to brand onto the packet.

The interesting part is in the center: \"-p tcp\" allows for a variety of criteries to be used for matching such as source port (--sport), destination port (--dport) or destination address (this is used at the end of the script, to put all LAN traffic into 1:10, where it goes \"around\" all the internet traffic. The destination IP is simply checked against 192.168.1.0, with a subnet mask of 255.255.255.0 - here written as /24 - which will match every IP from 192.168.1.0 to 192.168.1.255). Knowing that the lines should be pretty self-explanatory. UDP traffic can also be matched by specifying \"-p udp\" instead of \"-p tcp\", with otherwise the same options. This way you can also catch mldonkey traffic (or at least parts of it) with port ranges if the uid-approach (below) does not work for you.

mldonkey setup

The setup for mldonkey deserves a little more explanation. The -m option of the iptables command loads a module of iptables, capable of certain matching methods different from trivial port/address/etc. matches. \"-m owner\" loads uid, gid, pid or sid based matching and \"--uid-owner 1001\" tells the module to match (and mark) all packets originating from processes with the UID 1001. This works only if you have a user on your system dedicated to running mldonkey (or mlnet). To find out your UID, login as that user and type in \"id\".

Testing

At the end the marked packets are assigned to their respective queues. Marking alone doesn't do anything to the packets, so this step is necessary. Once your script is finished and tested (you can test it by setting mldonkey to a 0 upload limit, monitoring your bandwidth usage with iptraf and bwmon and then enabling the script. For better defined test results I recommend setting the ceil values very low (~ 3kpbs) while testing your settings. That will quickly show you whether it is working or not) your ping times should significantly decrease while uploading or, to be more exact, return to their old values without heavy network usage through mldonkey.


Traffic shaping in FreeBSD

To get traffic shaping to work on mldonkey in FreeBSD, you need to make sure you have a DUMMYNET-enabled ipfw firewall.

DUMMYNET is enabled in your kernconf, and should look something like this:

 
# For ipfw/natd 

options         IPFIREWALL 
options         IPDIVERT 
options         IPFIREWALL_DEFAULT_TO_ACCEPT 
options         IPFIREWALL_VERBOSE 

# For DUMMYNET packet shaping 
options         DUMMYNET 
options         HZ=1000 

If you don't know how to build yourself a new kernel/world, now would be an excellent time to learn.

Once the new kernel is in place, you will want to add the following to /boot/loader.conf

 
debug.mpsafenet=0 

Without it, ipfw *will* take down your machine when your mldonkey DUMMYNET pipe starts to get packets coming through it. This is a known issue with ipfw, and will one day get fixed, I imagine.

And make sure the firewall is able to run by tweaking /etc/rc.conf along the lines of:

 
# Firewall 
firewall_enable="YES" 
firewall_type="/etc/rc.firewall" 
firewall_method="dummynet" 
log_in_vain="NO" 
tcp_drop_synfin="NO" 
icmp_drop_redirect="YES" 

And add the ipfw rules to /etc/rc.firewall:

(Mine is a fancyish script that invokes ipfw rules in order, with common variables such as $WAN, $LAN etc, yours may not be)

 
# DLMonkey's dummynet rules
/sbin/ipfw add pipe 101 ip from any to any uid DLMonkey via $WAN in
/sbin/ipfw add pipe 102 ip from any to any uid DLMonkey via $WAN out
/sbin/ipfw pipe 101 config delay 100ms
/sbin/ipfw pipe 102 config delay 100ms

A more standard sort of ruleset would look like:

 
ipfw add 9001 pipe 101 ip from any to any uid mldonkey via rl0 in 
ipfw add 9002 pipe 102 ip from any to any uid mldonkey via rl0 out 
ipfw pipe 101 config bw 512 kbit/s delay 100 ms 
ipfw pipe 102 config bw 64 kbit/s delay 100 ms 

Both of these assume the user 'mldonkey' is running your mldonkey, which is probably going to be for the best if you're planning on shaping the traffic by UID - 'uid mldonkey' can be the username or UID number of the user who runs mldonkey, 'rl0' is the interface you connect out to the internets on.

Now you ought to be able to start up mldonkey (as the mldonkey user) and have it gracefully step aside a little when someone else wants to use the bandwidth. It's not a perfect solution, but it goes a long way towards keeping the donkey from eating *all* your e-carrots, so to speak.

Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox