This post originated from an RSS feed registered with Ruby Buzz
by Eric Hodel.
Original Post: Bandwidth Limiting with pf and ALTQ
Feed Title: Segment7
Feed URL: http://blog.segment7.net/articles.rss
Feed Description: Posts about and around Ruby, MetaRuby, ruby2c, ZenTest and work at The Robot Co-op.
Every now and then my neighbors end up chewing up too much of my bandwidth. In order to give my computers a more-reliable connection and keep the number of access points in my neighborhood low, I started limiting their traffic using ALTQ in the pf packet filter.
My router runs FreeBSD with a connection to the internet on one side and an Airport Extreme on the other end. My router handles all the network configuration (DHCP, DNS, firewall) and the Extreme is just a bridge. I've classified my hosts on the wifi network into hosts I know about that get assigned fixed addresses via DHCP and everybody else that gets assigned an address out of a DHCP pool.
ALTQ allows you to create a hierarchy of queues each with a particular amount of bandwidth. If a queue fills up width bandwidth you can either throw out the extra packets or borrow from one of the other queues. You can get some ideas of how to set up a hierarchy of queues from the examples on the ALTQ page.
For my network I chose to start with two queues one for my hosts and one for everybody else:
altq on $wifi_if cbq bandwidth 100Mb queue { mine, other }
queue mine bandwidth 98Mb priority 1 cbq(borrow)
queue other bandwidth 2Mb priority 7 cbq(default ecn)
This is much simpler than the ALTQ examples which allow prioritization of ACK packets and interactive sessions like SSH or IM connections, but I really don't care about the service of everybody else.
Since the queues are hierarchical, you end up with a 100Mb queue for all traffic on my wifi interface split into a 98Mb queue for myself and a 2Mb queue for everybody else. My queue gets top priority and can borrow bandwidth from everybody else. The other queue picks up the rest of the traffic and uses Explicit Congestion Notification as it fills up (which includes dropping packets).
Now we have to assign packets to the queues:
my_hosts = "192.0.2.1/27"
pass out quick on $wifi_if from any to $my_hosts queue mine
pass out on $wifi_if from any to any queue other
After reloading pf and letting traffic go by for a while you can see the queue in action: