QoS Traffic Shaper for home and office | P2P, VoIP, games
Posted by dariusDec 22
The below is a script to turn a standard Linux box into a very good router, featuring traffic shaping and QoS rule sets for an optimal user experience and a fair connection prioritisation under heavy network load.
I’m running it on a 1Ghz CPU Gentoo Linux box, sharing a cable connection with other 11 machines and an access point opened to rest of the world.
The tool can be run on any Linux distribuition, not on a Windows machine, if it’s what you are looking for.
By using this script, anyone can exchange files on the Internet with any P2P application like DC++, BitTorrent, Emule, watch Youtube video clips, talk to people with Skype, MSN Messenger or Ekiga, play realtime online games, and have all those connections work flawlessly, audio/video VoIP calls without cloggering, online gaming without delays, P2P as fast as possible.
The router script doesn’t do any magic actually. It just makes sure traffic is routed the proper way, and gives the proper applications the proper bandwidth at the proper time.
The open WiFi network is also isolated from the home network through iptables rules, and it has its own class of bandwidth priority, so unauthenticated guests can use the unused bandwidth without slowing down the home network, but are also isolated from it, and cannot access internal data.
Technically speaking, the router uses 7 HTB iproute2 classes and some SFQ where appropriate, making a fairly good distinction between real time applications and the bulk.
This shaper is a home/SOHO optimised version of similar scripts that can be found at LARTC, which also hosts a comprehensive tutorial of iproute2 and its traffic policing capabilities.
Tip: Some tweaking of the script may be required anyway. The traffic shaper must always be adjusted to the actual upload bandwidth minus a bit, and VoIP applications may need some tweak of their buffers: large data buffers mean more voice latency – which could be confusing – but no clogging. Too small buffers may easily lead to clogging, but the latency is minimal. I leave you to set the best value for latency on your network. Here is a link for a direct download, if you prefer that.
The script comes with absolutely no warranty of any kind. I recommend reading it through, understanding it, tweaking it, and then running it, if ever
#!/bin/bash
######################################################################
# D-shaper - DSL/Cable modem outbound traffic shaper and
# prioritizer, Based on the ADSL/Cable
# wondershaper (www.lartc.org)
# optimized for newer kernels by Ðarius.
# - www.darius.it -
# USAGE:
# shape {upstream interface} {maximum rate}
# shape status
# I.E.:
# # for a 256Kbps upstream connection (put a smaller
# # value if it doesn't work perfectly
# #
# shape eth2 220
# #
# # fine tune the upstream value for your needs
#
######################################################################
UPSTREAM=$1 # upstream interface
TRUSTED=via # trusted home network
UNTRUSTED=none # another untrusted network interface (i.e.: eth3)
# you could have around
# (i.e.: a subnet You wanna grant limited
# bandwidth to)
if [ ! -e /sys/class/net/$UNTRUSTED ]; then
UNTRUSTED=""
fi
RATEUP=$2 # Upstream maximum bitrate
RATE_UNTRUSTED=200 # Maximum DOWNLOAD bitrate for your secondary
# network, if any
MTUUP=576 # A commonly suggested optimal value for the
# internet.
# Change it on your needs.
if [ "$1" = "status" ]
then
for i in $(ls /sys/class/net); do
echo "-----------------------------"
echo "[qdisc] $i"
tc -s qdisc show dev $i
echo "[class] $i"
tc -s class show dev $i
echo "[filter] $i"
tc -s filter show dev $i
done
exit
fi
# Reset everything to a known state (cleared)
for i in $(ls /sys/class/net); do
tc qdisc del dev $i root 2>/dev/null
done
# clear entries from iptables
for i in $(ls /sys/class/net); do
iptables -t mangle -D POSTROUTING -o $i \
-j MYSHAPER-OUT 2> /dev/null > /dev/null
done
iptables -t mangle -F MYSHAPER-OUT 2> /dev/null > /dev/null
iptables -t mangle -X MYSHAPER-OUT 2> /dev/null > /dev/null
if [ "$1" = "stop" ]
then
echo "Shaping removed."
exit
fi
if [ -z $1 ]; then
echo 'Specify output device'
exit
fi
if [ -z $2 ]
then
echo 'Specify output rate (Kbit/s)'
exit
fi
###########################################################
#
# UNTRUSTED network limits
if [ ! -e /sys/class/net/$UNTRUSTED ]; then
tc qdisc add dev $UNTRUSTED root handle 1: tbf rate \
$RATE_UNTRUSTED burst 10k latency 1s
fi
###########################################################
# Outbound Shaping (limits total bandwidth to RATEUP)
###########################################################
# set queue size to give latency of about 2 seconds on
# low-prio packets
ip link set dev $UPSTREAM qlen 30
# changes mtu on the outbound device. Lowering the mtu
# will result in lower latency but will also cause slightly
# lower throughput due to IP and TCP protocol overhead.
# 576 is a quite widespread value
ip link set dev $UPSTREAM mtu $MTUUP
# add HTB root qdisc
tc qdisc add dev $UPSTREAM root handle 1: htb default 26
# add main rate limit classes
tc class add dev $UPSTREAM parent 1: classid 1:1 htb \
rate ${RATEUP}kbit
# setting main classes: Each class can lend and borrow bandwidth
# from each-other
# P2P has the lowest guaranteed bandwidth and lowest priority.
# P2P: 1/20 of the total bandwidth.
# Real time class (voip) has 1/3 of the remaining 19/20th
# and all other classes share what still
# equals ((bandwidth * 19/20)/5)
# Change the following values according to your needs.
# Real Time
tc class add dev $UPSTREAM parent 1:1 classid 1:20 htb \
rate $[($RATEUP*19/20)/3]kbit \
ceil ${RATEUP}kbit quantum 1 prio 0
# Interactive
tc class add dev $UPSTREAM parent 1:1 classid 1:21 htb \
rate $[($RATEUP*19/20)/15]kbit \
ceil ${RATEUP}kbit quantum 1 prio 1
# Games
tc class add dev $UPSTREAM parent 1:1 classid 1:22 htb \
rate $[($RATEUP*19/20)/15]kbit \
ceil ${RATEUP}kbit quantum 1 prio 2
# Low ports
tc class add dev $UPSTREAM parent 1:1 classid 1:23 htb \
rate $[($RATEUP*19/20)/15]kbit \
ceil ${RATEUP}kbit quantum 1 prio 3
# User apps
tc class add dev $UPSTREAM parent 1:1 classid 1:24 htb \
rate $[($RATEUP*19/20)/15]kbit \
ceil ${RATEUP}kbit quantum 1 prio 4
# Bulk transfers
tc class add dev $UPSTREAM parent 1:1 classid 1:25 htb \
rate $[($RATEUP*19/20)/15]kbit \
ceil ${RATEUP}kbit quantum 1 prio 5
# P2P
tc class add dev $UPSTREAM parent 1:1 classid 1:26 htb \
rate $[$RATEUP/20]kbit \
ceil ${RATEUP}kbit quantum 1 prio 6
# attach qdisc to leaf classes - here we at SFQ to each
# priority class. SFQ makes sure that
#within each class connections will be treated (almost) fairly.
# no sfq 'cause we should have almost no queue here.
# Better dropping packets than delay them in VoIP
tc qdisc add dev $UPSTREAM parent 1:20 handle 20: pfifo limit 5
tc qdisc add dev $UPSTREAM parent 1:21 handle 21: pfifo limit 30
tc qdisc add dev $UPSTREAM parent 1:22 handle 22: pfifo limit 30
# long queue here and sqf not to drop too much packets,
# if possible
tc qdisc add dev $UPSTREAM parent 1:23 handle 23: sfq perturb 10 \
limit 200
tc qdisc add dev $UPSTREAM parent 1:24 handle 24: sfq perturb 10 \
limit 200
tc qdisc add dev $UPSTREAM parent 1:25 handle 25: sfq perturb 10 \
limit 200
# longest queue for really bulk transfers
tc qdisc add dev $UPSTREAM parent 1:26 handle 26: sfq perturb 10 \
limit 300
# add MYSHAPER-OUT chain to the mangle table in iptables
# - this sets up the table we'll use
# to filter and mark packets.
iptables -t mangle -N MYSHAPER-OUT
iptables -t mangle -I POSTROUTING -o $UPSTREAM -j MYSHAPER-OUT
# Actually classify packets using the CLASSIFY iptables target,
# instead of others.
# Should work on 2.6 kernels, should on patched 2.5 ones.
# If not, check your iproute2/iptables installation and proper
# netfilter kernel support.
# 1:20 Real time
# ensure min delay by TOS field
iptables -t mangle -A MYSHAPER-OUT -m tos --tos 0x10 -j CLASSIFY \
--set-class 1:20
# VoIP,RTP,RTSP, (23399, 35724 or others for Skype: set your
# ports here)
iptables -t mangle -A MYSHAPER-OUT -p udp -m multiport \
--ports 5060:5063,8000,554,23399,35724 \
-j CLASSIFY --set-class 1:20
# RTSP
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 554 \
-j CLASSIFY --set-class 1:20
# NTP
iptables -t mangle -A MYSHAPER-OUT -p udp --dport 123 \
-j CLASSIFY --set-class 1:20
# 1:21 Small Interactive
# ICMP
iptables -t mangle -A MYSHAPER-OUT -p icmp \
-j CLASSIFY --set-class 1:21
# SSH, not SCP
iptables -t mangle -A MYSHAPER-OUT -p tcp -m multiport \
--ports ssh -m limit --limit 10/second \
-j CLASSIFY --set-class 1:21
# telnet
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport telnet \
-j CLASSIFY --set-class 1:21
# telnet
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport telnet \
-j CLASSIFY --set-class 1:21
# DNS
iptables -t mangle -A MYSHAPER-OUT -p udp --dport domain \
-j CLASSIFY --set-class 1:21
iptables -t mangle -A MYSHAPER-OUT -p tcp \
--tcp-flags SYN,RST,ACK SYN,FIN \
-j CLASSIFY --set-class 1:21
# 1:22 Bulk Interactive
# MSN/Webcam
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 6891 \
-j CLASSIFY --set-class 1:22
# Windows remote desktop
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 3389 \
-j CLASSIFY --set-class 1:22
# 1:22 Games
# 1:23 Low port services
# Default for low port traffic
iptables -t mangle -A MYSHAPER-OUT -p tcp --sport 0:1024 \
-j CLASSIFY --set-class 1:23
# ""
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport 0:1024 \
-j CLASSIFY --set-class 1:23
# 1:24 User apps
# ICQ (add tcp 4000 for old icq protocols, if needed), MSN
iptables -t mangle -A MYSHAPER-OUT -p tcp -m multiport \
--dports 5190,1863 -j CLASSIFY --set-class 1:24
# Local services for the Internet
# Local web server
#iptables -t mangle -A MYSHAPER-OUT -p tcp --sport http \
# -j CLASSIFY --set-class 1:25
# Local smtp server
#iptables -t mangle -A MYSHAPER-OUT -p tcp --sport smtp \
# -j CLASSIFY --set-class 1:25
# small packets (probably just ACKs)
iptables -t mangle -A MYSHAPER-OUT -p tcp -m length --length 60 \
-j CLASSIFY --set-class 1:22
# 1:25 Bulk transfers
# ftp-data port, low prio
iptables -t mangle -A MYSHAPER-OUT -p tcp --dport ftp-data \
-j CLASSIFY --set-class 1:25
# 1:26 P2P, etc. Everything that hasn't been classified since now,
# is considered bulk
# like P2P, and will have it's lowest priority
# P2P
#iptables -t mangle -A MYSHAPER-OUT -m ipp2p --ipp2p \
# -j CLASSIFY --set-class 1:26
##################################################################
# Done with outbound shaping
##################################################################
echo "Outbound shaping added to $UPSTREAM. Rate: ${RATEUP}Kb/s."
# For now I don't handle inbound shaping. Maybe in a
# further version
exit
8 comments
Comment by Free VOIP Calls on 2010/02/08 at 08:09
VOIP is the best. You are able to do so many things with it unlike the normal telephones. I like how its able to use the internet because this saves us money. I also call internationally to Bangladesh and India and so its way cheaper than normal calls. This is a good post about VOIP, keep it up.
Comment by Trevor on 2010/02/09 at 09:14
This sounds like exactly what I need, I have a linux router/server that hosts files and where I run my own p2p etc. so I don’t have to restart all my transfers if I reboot my workstation. I share this connection out to several other people both wired and wireless and they all run p2p of course. I use sype a fair amount and i’d like to make it sure web browser was still somewhat snappy despite whatever me or anyone else is downloading. Implementing something like is very new to me, so yes this is going to be a noob question. How to I acutally have my linux box run this script when its boots? or run it it all, I just have no experience running scripts, lol. do I copy it into a file/create a file in “/etc” for example?
thanks in advance for any help anyone can offer
Comment by darius on 2010/02/14 at 06:47
Greetings,
what I have is an init script that runs at boot, like the one below. You may call it /etc/init.d/qos, for example:
#!/sbin/runscriptopts="reload"
depend() {
before net
use logger
}
start() {
ebegin "Starting QoS"
shape eth2 950
eend $?
}
stop() {
ebegin "Stopping router"
shape stop
eend $?
}
reload() {
begin "Resetting router"
start
eend $?
}
Let me discuss some assumptions
I expect init scripts to be in the /etc/init.d folder. You might have a distribution that keeps them elsewhere
The shaper script should be somewhere, like /usr/local/sbin/shape, and have the executable flag on for root (chmod 0700 would be ok).
The init script itself has to be made executable.
chmod 0755 /etc/init.d/qosrun as root would do the trick.The init script has also to be registered for autostart. On Gentoo we do this with an
rc-update add qos boot, but on other distributions the grammar IS different. Please check yoursHope this helps
Best,
DM
Comment by Christian Louboutin on 2010/06/10 at 13:53
Thanks for this useful article.
Comment by Wordpress Themes on 2010/06/11 at 12:34
Amiable post and this post helped me alot in my college assignement. Thanks you for your information.
Comment by Gainge on 2010/07/27 at 14:19
I don’t generally reply to content but I’ sure will in this case. Seriously a big thumbs up for this 1 C CLass IP hosting!
Comment by organic tea on 2010/07/31 at 00:05
great share, great article, very usefull for me…thank you
Comment by Ghita on 2010/08/23 at 21:38
nice work !!