Bandwidth limiting on OpenBSD 6.8

Comment on Mastodon

This is a February 2021 update of a text originally published in April 2017.

Introduction

I will explain how to limit bandwidth on OpenBSD using its firewall PF (Packet Filter) queuing capability. It is a very powerful feature but it may be hard to understand at first. What is very important to understand is that it's technically not possible to limit the bandwidth of the whole system, because once data is getting on your network interface, it's already there and got by your router, what is possible is to limit the upload rate to cap the download rate.

OpenBSD pf.conf man page about queuing

Prerequisites

My home internet access allows me to download at 1600 kB/s and upload at 95 kB/s. An easy way to limit bandwidth is to calculate a percent of your upload, that should apply that ratio to your download speed as well (this may not be very precise and may require tweaks).

PF syntax requires bandwidth to be defined as kilo-bits (kb) and not kilo-bytes (kB), multiplying by 8 allow to switch from kB to kb.

Configuration

Edit the file /etc/pf.conf as root and add the following before any pass/match/drop rules, in the example my main interface is em0.

# we define a main queue (requirement)
queue main on em0 bandwidth 1G

# set a queue for everything
queue normal parent main bandwidth 200K max 200K default

And reload with `pfctl -f /etc/pf.conf` as root. You can monitor the queue working with `systat queue`

QUEUE        BW/FL SCH      PKTS    BYTES   DROP_P   DROP_B QLEN
main on em0  1000M fifo        0        0        0        0    0
 normal      1000M fifo   535424 36032467        0        0   60

More control (per user / protocol)

This is only a global queuing rule that will apply to everything on the system. This can be greatly extended for specific need. For example, I use the program "oasis" which is a daemon for a peer to peer social network, sometimes it has upload burst because someone is syncing against my computer, I use the following rule to limit the upload bandwidth of this user.

# within the queue rules
queue oasis parent main bandwidth 150K max 150K

# in your match rules
match on egress proto tcp from any to any user oasis set queue oasis

Instead of a user, the rule could match a "to" address, I used to have such rules when I wanted to limit my upload bandwidth for uploading videos through peertube web interface.