LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Networking
User Name
Password
Linux - Networking This forum is for any issue related to networks or networking.
Routing, network cards, OSI, etc. Anything is fair game.

Notices


Reply
  Search this Thread
Old 03-29-2010, 07:36 AM   #1
jomen
Senior Member
 
Registered: May 2004
Location: Leipzig/Germany
Distribution: Arch
Posts: 1,687

Rep: Reputation: 55
traffic shaping using tc and iptables fw mark


I need to ask the experts because I'm not sure I did this right.
The aim is to limit each one of many users to a max. bandwidth of 512kbit while all users share the full bandwidth of 1400kbit.

Code:
# there are 5 priorities
PRIO_1="1"
PRIO_2="2"
PRIO_3="3"
PRIO_4="4"
PRIO_5="5"
I use different matches to set these using "... -j MARK --set-mark $PRIO_x"

I then re-mark based on IP Address.
Basically an offset of 5 per IP

PRIO_1="1" becomes NEWPRIO_1="6"
PRIO_2="2" becomes NEWPRIO_2="7"
...
PRIO_5="5" becomes NEWPRIO_5="10"
...


The statistics
Code:
tc -s -d qdisc show dev $OUTDEVICE
do not show any traffic going through the (leaf ?) qdiscs I created like this:

Code:
# the root qdisc
tc qdisc add dev $OUTDEVICE root handle 1: htb default 999 r2q 1

# root class
tc class add dev $OUTDEVICE parent 1: classid 1:1 htb rate $LINKRATE burst $BURST

# parent class - one class for each user
tc class add dev $OUTDEVICE parent 1:1 classid 1:2 htb rate $RATE ceil $CEIL burst $BURST
tc class add dev $OUTDEVICE parent 1:1 classid 1:3 htb rate $RATE ceil $CEIL burst $BURST
tc class add dev $OUTDEVICE parent 1:1 classid 1:4 htb rate $RATE ceil $CEIL burst $BURST
...
...
tc class add dev $OUTDEVICE parent 1:1 classid 1:33 htb rate $RATE ceil $CEIL burst $BURST
tc class add dev $OUTDEVICE parent 1:1 classid 1:34 htb rate $RATE ceil $CEIL burst $BURST



# filter which SHOULD direct traffic into leaf class 1:2 
# identified by "handle" $NEWPRIO_1 through $NEWPRIO_5, which is the fw mark I set previously

tc filter add dev $OUTDEVICE parent 1:2 protocol ip prio $PRIO_1 handle $NEWPRIO_1 fw flowid 1:2
tc filter add dev $OUTDEVICE parent 1:2 protocol ip prio $PRIO_2 handle $NEWPRIO_2 fw flowid 1:2
tc filter add dev $OUTDEVICE parent 1:2 protocol ip prio $PRIO_3 handle $NEWPRIO_3 fw flowid 1:2
tc filter add dev $OUTDEVICE parent 1:2 protocol ip prio $PRIO_4 handle $NEWPRIO_4 fw flowid 1:2
tc filter add dev $OUTDEVICE parent 1:2 protocol ip prio $PRIO_5 handle $NEWPRIO_5 fw flowid 1:2

# the above is just the filter for one IP - there is these 5 lines for each IP really - with "parent" and "flowid" adapted
and of course I scripted this - since it would be too much writing - this is just to show it here


My question is:
is my usage of
"handle $NEWPRIO_x fw"
in the filter definition correct to direct traffic based on this fw mark into flowid 1:2 (...through to flowid 1:34 )?

...because: the root class shows traffic - the leaf classes 1:2 ... 1:34 do not
Which is what I wanted - filter based on the re-marked fw mark which is represented by "$NEWPRIO_x".

Can anyone point out where my mistake could be?
Or how I could use the fw mark "$NEWPRIO_x" to direct traffic through filters to a specific qdisc?
 
Old 03-30-2010, 02:18 AM   #2
mpier
Member
 
Registered: Jan 2008
Location: Poland
Distribution: Slackware, Arch
Posts: 38

Rep: Reputation: 17
Hi,
I cannot understand your conception (what do you wont to achieve), bu change parent of filters to 1: (filter ... parent 1. Now the packets will be directed to 1:2 class.
 
Old 03-30-2010, 02:31 AM   #3
razerstam1
LQ Newbie
 
Registered: Mar 2010
Posts: 1

Rep: Reputation: 0
I cannot understand your conception
 
Old 04-15-2010, 06:14 AM   #4
jomen
Senior Member
 
Registered: May 2004
Location: Leipzig/Germany
Distribution: Arch
Posts: 1,687

Original Poster
Rep: Reputation: 55
I'm sorry for the late reply and thank you for trying to understand what I meant

Seeing the whole script would have helped I suppose.
I was reluctant to post it - not only because it is quite long...

I'll attach a version for a somewhat different purpose - so you see what is there now.
enjoy
It is for a Gateway in a wireless mesh network and to be run on a OpenWRT home router like the Linksys WRT54GL.

Basically I was not sure where to direct the filters output to - to the leaf class or to the main class.
Directing it to main seems to work.
I wasn't even sure whether the filters where actually working at all.

But that might come from me testing the script on my machine - instead of a router with 3 different interfaces.
...and that I use the PREROUTING chain... but I still don't fully understand.
Packets get marked - the mark is used to filter them into the right qdisc.

If I change PREROUTING to POSTROUTING all seems to work - but I still see traffic in the default class.
And I don't know where it comes from...

have a look:

Code:
#!/bin/sh

# these ranges will be used to prioritize traffic from LAN over Freifunk - and both of these over WLAN-Clients later on
# whoever is on the LAN has priority this way - this is intended to treat the owner before all others
# so he does not even notice that he is sharing his link to freifunk
LANIP="192.168.1.0/24"
FFIP="104.61.0.0/16"
FFWLAN="10.104.56.1/27"

RANGE="$LANIP $FFIP $FFWLAN"

# which Interface ?
WANDEVICE=eth1

# LINKRATE needs to be adjusted to what is really there minus a little
# to make sure the queue is controlled here and the link never gets congested
# because the queue is full 

LINKRATE="460kbit"
RATE="380kbit"
CEIL=$LINKRATE
BURST="12k"

### no need to change below here ###

INSMOD=`which insmod 2> /dev/null`
MODULES="cls_fw sch_prio sch_sfq sch_htb"

LOCK='/var/lock/shaper.lock'
TC=`which tc 2> /dev/null`
IPTABLES=`which iptables 2> /dev/null`

MANGLE="$IPTABLES -t mangle"
FILTERS='protomatch packetsize_1 packetsize_2 packetsize_3 packetsize_udp_1 packetsize_udp_2 packetsize_icmp nomatch unique'
CHAIN="PREROUTING"

# priorities to be used later
# 1 for small packets of important protocols
# 2 important data (large packets tcp)
# 3 important data (large packets udp)
# 4 small packets (ACK) unimportant protocols
# 5 data unimportant protocols
# 6 is lowest

PRIO_1="1"
PRIO_2="2"
PRIO_3="3"
PRIO_4="4"
PRIO_5="5"
PRIO_6="6"

load_modules () {
	for module in $MODULES; do
		$INSMOD "$module" > /dev/null 2>&1
	done
}

get_default_class () {
	DEFAULT=10
	for range in $RANGE; do
	DEFAULT=$(( $DEFAULT+10 ))
	done
}

relabel () {
	NEWPRIO_1=$(( $PRIO_1+$OFFSET ))
	NEWPRIO_2=$(( $PRIO_2+$OFFSET ))
	NEWPRIO_3=$(( $PRIO_3+$OFFSET ))
	NEWPRIO_4=$(( $PRIO_4+$OFFSET ))
	NEWPRIO_5=$(( $PRIO_5+$OFFSET ))
	NEWPRIO_6=$(( $PRIO_6+$OFFSET ))
}

create_chains () {
        for filter in $FILTERS; do
                $MANGLE -N $filter
                $MANGLE -F $filter
                $MANGLE -A $CHAIN -j $filter
        done
}


delete_chains () {
        for filter in $FILTERS; do
                $MANGLE -D $CHAIN -j $filter
                $MANGLE -F $filter
                $MANGLE -X $filter
        done
}


populate_chains () {

	# ICMP
	$MANGLE -A protomatch -p icmp -j packetsize_icmp

	# DNS and other important udp services - more if wanted
	$MANGLE -A protomatch -p udp -m multiport --dports 53,1812,1813,3478,3479,5060,5061 -j packetsize_udp_1
	$MANGLE -A protomatch -p udp -j packetsize_udp_2

	# match known and (un)wanted protocols so we can prioritize these later
	$MANGLE -A protomatch -p tcp -m multiport --dports 22,25,80,110,134,220,443,465,995,1723,1812,1813,4500,5060,5061 -j packetsize_1
	$MANGLE -A protomatch -p tcp -m multiport --dports 20,21,119,123 -j packetsize_2
	$MANGLE -A protomatch -p tcp -j packetsize_3
	$MANGLE -A protomatch -j nomatch

	# match wanted proto by size of packet
	$MANGLE -A packetsize_1 -m length --length :99 -j MARK --set-mark $PRIO_1
	$MANGLE -A packetsize_1 -m mark --mark $PRIO_1 -j unique
	$MANGLE -A packetsize_1 -m length --length 100: -j MARK --set-mark $PRIO_2
	$MANGLE -A packetsize_1 -m mark --mark $PRIO_2 -j unique
	$MANGLE -A packetsize_1 -j nomatch

	# match not so important proto by size
	$MANGLE -A packetsize_2 -m length --length :99 -j MARK --set-mark $PRIO_4
	$MANGLE -A packetsize_2 -m mark --mark $PRIO_4 -j unique
	$MANGLE -A packetsize_2 -m length --length 100: -j MARK --set-mark $PRIO_5
	$MANGLE -A packetsize_2 -m mark --mark $PRIO_5 -j unique
	$MANGLE -A packetsize_2 -j nomatch

	# match all other protos by size
	$MANGLE -A packetsize_3 -m length --length :99 -j MARK --set-mark $PRIO_4
	$MANGLE -A packetsize_3 -m mark --mark $PRIO_4 -j unique
	$MANGLE -A packetsize_3 -m length --length 100: -j MARK --set-mark $PRIO_6
	$MANGLE -A packetsize_3 -m mark --mark $PRIO_6 -j unique
	$MANGLE -A packetsize_3 -j nomatch

	# mark important udp traffic by packetsize
	$MANGLE -A packetsize_udp_1 -m length --length :99 -j MARK --set-mark $PRIO_1
	$MANGLE -A packetsize_udp_1 -m length --length 100: -j MARK --set-mark $PRIO_3
	$MANGLE -A packetsize_udp_1 -j unique

	# mark other udp traffic by packetsize
	$MANGLE -A packetsize_udp_2 -m length --length :99 -j MARK --set-mark $PRIO_4
	$MANGLE -A packetsize_udp_2 -m length --length 100: -j MARK --set-mark $PRIO_6
	$MANGLE -A packetsize_udp_2 -j unique

	# size-check ICMP - to be tested (76 or a little more should be normal)
	$MANGLE -A packetsize_icmp -p icmp -m length --length :99 -j MARK --set-mark $PRIO_1
	$MANGLE -A packetsize_icmp -p icmp -m length --length 100: -j MARK --set-mark $PRIO_6
	$MANGLE -A packetsize_icmp -j unique

	# in case we had a protocol not matched or we missed something - it lands here
	# we still give small packets priority over large ones but put both into low prio
	$MANGLE -A nomatch -m length --length :99 -j MARK --set-mark $PRIO_4
	$MANGLE -A nomatch -m length --length 100: -j MARK --set-mark $PRIO_6
	$MANGLE -A nomatch -j unique
}

make_unique () {
	
	# make the mark unique depending on which IP-Range a user comes from

	OFFSET=0

	for range in $RANGE; do

	relabel

	$MANGLE -A unique -s $range -m mark --mark $PRIO_1 -j MARK --set-mark $NEWPRIO_1
	$MANGLE -A unique -s $range -m mark --mark $PRIO_2 -j MARK --set-mark $NEWPRIO_2
	$MANGLE -A unique -s $range -m mark --mark $PRIO_3 -j MARK --set-mark $NEWPRIO_3
	$MANGLE -A unique -s $range -m mark --mark $PRIO_4 -j MARK --set-mark $NEWPRIO_4
	$MANGLE -A unique -s $range -m mark --mark $PRIO_5 -j MARK --set-mark $NEWPRIO_5
	$MANGLE -A unique -s $range -m mark --mark $PRIO_6 -j MARK --set-mark $NEWPRIO_6

	OFFSET=$(( $OFFSET+6 ))

	done

	$MANGLE -A unique -j ACCEPT
}


filter_on () {
	create_chains
	populate_chains
	make_unique
}


start_shaping () {
	get_default_class
	# root qdisc
	tc qdisc add dev $WANDEVICE root handle 1: htb default $DEFAULT r2q 1

	# root class
	tc class add dev $WANDEVICE parent 1: classid 1:1 htb rate $LINKRATE ceil $LINKRATE burst $BURST

	# user classes
	OFFSET=0
	ID=10
	CLASSPRIO=1

	for range in $RANGE; do

	relabel

	# one class for each IP-range (LAN, Freifunk, WLAN-Clients)
	tc class add dev $WANDEVICE parent 1:1 classid 1:$ID htb rate $RATE ceil $CEIL burst $BURST prio $CLASSPRIO

	# attach 6 filters ordered by priority to each class
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_1 handle $NEWPRIO_1 fw flowid 1:$ID
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_2 handle $NEWPRIO_2 fw flowid 1:$ID
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_3 handle $NEWPRIO_3 fw flowid 1:$ID
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_4 handle $NEWPRIO_4 fw flowid 1:$ID
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_5 handle $NEWPRIO_5 fw flowid 1:$ID
	tc filter add dev $WANDEVICE parent 1:0 protocol ip prio $PRIO_6 handle $NEWPRIO_6 fw flowid 1:$ID

	tc qdisc add dev $WANDEVICE parent 1:$ID sfq perturb 10

	OFFSET=$(( $OFFSET+6 ))
	ID=$(( $ID+10 ))
	CLASSPRIO=$(( $CLASSPRIO+1 ))
	done

	# add a default class
	tc class add dev $WANDEVICE parent 1:1 classid 1:$DEFAULT htb rate $RATE ceil $CEIL prio $(( $CLASSPRIO+1 ))
}


stop_shaping () {
	tc qdisc del dev $WANDEVICE root
}


runcheck () {
		if [ -f $LOCK ]; then
			echo "script is already running - please check with "show_qdisc" and/or" show_filters""
			echo "...or some other thing went wrong"
			exit
				else
			echo "starting to classify and shape traffic on $WANDEVICE"
		fi
}


lockcheck () {
		if [ -f $LOCK ]; then
			rm $LOCK
			echo "removed lockfile as well as all rules and filters"
				else
			echo "there was no lockfile to remove - NOT CLEANLY SHUT DOWN!"
			echo "some rules and filters may still be present"
			echo "please investigate before restarting the script"
		fi
}


case $1 in
        start)
		runcheck
		load_modules
		filter_on
		start_shaping
		touch $LOCK
	;;
	stop)
		stop_shaping
		delete_chains
		lockcheck
	;;
	show_qdisc)
		echo "current shaper configuration:"
		echo "--------------------qdisc: -------------------------------"
		tc -s -d qdisc show dev $WANDEVICE
		echo "--------------------classes: -----------------------------"
		tc -s -d class show dev $WANDEVICE
		echo "--------------------done----------------------------------"
	;;
	show_filters)
		echo "current state of filters - iptables"
		$MANGLE -nvL
	;;
	*)
		echo "usage: $0 start|stop|show_qdisc|show_filters"
	;;
esac

Last edited by jomen; 04-15-2010 at 06:28 AM.
 
0 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Problem with Traffic Shaping and HTTP Traffic. redvivi Linux - Networking 1 11-29-2008 12:23 PM
traffic shaping help monohouse Linux - Networking 22 11-06-2008 08:38 AM
Traffic shaping (limiting outgoing bandwidth of all TCP-traffic except FTP/HTTP) ffkodd Linux - Networking 3 10-25-2008 12:09 AM
Traffic-shaping with iptables Quantum0726 Linux - Networking 7 08-21-2005 11:39 PM
Traffic Shaping nemesisza Linux - Networking 1 03-21-2004 05:52 PM

LinuxQuestions.org > Forums > Linux Forums > Linux - Networking

All times are GMT -5. The time now is 08:37 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration