Sunday, September 11, 2016
Saturday, September 10, 2016
Until recently I have been using a Raspberry Pi as my router and firewall, which worked reasonably well, though some useful features were lacking from the kernel. Within the past few months, my ISP increased the bandwidth of my plan and my pi could no longer keep up. So I upgraded my router to an "old" intel core i5 laptop. With that came an up to date linux kernel with it's full suite of packet shaping tools.
I have always used packet shaping on my router to help keep latency low. Low latency can be achieved under heavy bandwidth utilization by sending a little slower than the service plan allows, thus keeping modem and router buffers relatively empty. Latency increases when buffers fill up with data packets. This is known as bufferbloat. It is most effective to shape outbound traffic to the internet simply because I have full control over how fast I send data down the pipe to my ISP. Packet shaping, or rather policing downstream traffic is not as easy because I really have no control over how fast servers send data to me. Generally the best you can do is drop some packets to force the TCP layer to just slow down. In the past I have found that in order to avoid high latency during heavy downstream utilization required setting the ingress policing filter rate to a value substantially lower than my available bandwidth, say 75% of my available downstream bandwidth. Obviously this means I could never utilize the link's full capacity. Additionally, a single heavy downstream connection never seemed to utilize the maximum configured ingress rate. These were problems I wanted to solve with my new router setup.
Usually the only way you can limit the flow of downstream data is with an ingress policing filter with a rate limit, dropping packets when the preset data rate is exceeded. The more advanced packet shaping methods are only available as egress (upload) filters. However the linux kernel provides the Intermediate Functional Block device (IFB) to help with using advanced packet shaping methods with ingress data. When setup, it is an intermediate device that you can funnel ingress data to, and shape it as egress data. The Pi's kernel lacked the IFB device, making it difficult to shape inbound traffic.
I tried a few different packet shaping filters when setting up the IFB device, none of them worked as well as I had hoped, until I tried CoDel. I mostly followed the instruction found on this Gentoo traffic shaping post, though modified for my needs. The code below is the script I have been using for a while which seems to work well. A GitHub repository can be found at https://github.com/axlecrusher/packetshaping