0

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?

1 Answers1

0

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 with tc 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)

iptables -A INPUT -p tcp --dport 8128:8191 -m limit --limit 5/seconds -j ACCEPT
iptables -A INPUT -p tcp --dport 8128:8191 -j DROP

You need this two lines, first will accept first 5 packets every second for all ip together and second drop everything over it.

  • Thanks a lot Martin, you made my day. Alas I can't upvote until I get more rep. I'm chosing the iptables solution which is good enough. Rebuilding a kernel would make my automated deployment too complicated. – Laurent Caillette Oct 24 '15 at 13:13