I'm trying to rate-limit all incoming traffic on ports 8128-8191. I've read everything I found, checked everything ten times, it still doesn't work.
The commands:
tc qdisc del dev eth0 root
tc qdisc add dev eth0 root handle 1: htb default 1
tc class add dev eth0 parent 1:0 classid 1:1 htb rate 1kbit ceil 1kbit
tc filter add dev eth0 parent 1:0 prio 1 protocol ip u32 match ip dport 8128 0xFFC0 classid 1:1
This is how I calculated the mask:
expected = lowest port = 0b_0001_1111_1100_0000 = 0x1FC0 = 8128d
mask = highest port = 0b_1111_1111_1100_0000 = 0xFFC0
highest port = 0b_0001_1111_1111_1111 = 0x1FFF = 8191d
The output:
#tc -s class show dev eth0
class htb 1:1 root prio 0 rate 1000bit ceil 1000bit burst 1600b cburst 1600b
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 0 borrowed: 0 giants: 0
tokens: 200000000 ctokens: 200000000
# tc filter show dev eth0
filter parent 1: protocol ip pref 1 u32
filter parent 1: protocol ip pref 1 u32 fh 800: ht divisor 1
filter parent 1: protocol ip pref 1 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
match 00001fc0/0000ffc0 at 20
I send a flow of bytes from my workstation with:
cat /dev/urandom | pv -L 3k | nc -nvv ${SERVER_ADDRESS} 8128
On the server I receive them with:
nc -nvvl -p 8128 > /dev/null
I check usage of eth1 with the excellent iptraf and the throughput remains stuck to 3 kbit/s and more, and there is no increase in the counters of class htb 1:1
.
I believe I'm good with the masks. I also tried something simpler with dport 8128 0xFFFF
with no more results.
When displaying the filter, the at 20
seems correct because IP header is 20 byte long. The source and the destination ports are the first 4 bytes, so 32-bit match is correct. I don't understand the other values.
I'm using Debian 7:
# uname -a
Linux node-1 3.2.0-4-amd64 #1 SMP Debian 3.2.68-1+deb7u5 x86_64 GNU/Linux
I also cleared everything in iptables before trying the above.
Maybe I messed up something in the manner I connect the filter to a class. Maybe there is some kernel option I forgot to activate.
Any insights?
Best Answer
1) Limiting (shaping) input traffic with
tc
is difficult with standard linux kernel. You can try IMQ patch http://www.linuximq.net/ for your kernel. You need patch iptables too. Then you can "mark" packet for go to IMQ device, and withtc
on imq0 device you can shaping traffic as you want.2) Another easy but not accurate solution is using iptables, but it is based on packet counts (you need to approximate average packet size for your protocol/connection)
You need this two lines, first will accept first 5 packets every second for all ip together and second drop everything over it.