Packet Filter allows you to manage bandwidth by creating queues and assigning packets to them; queues must be attached to a specific network interface and are organized in a tree hierarchy, i.e. each queue can have further child queues.
Packet queueing is managed through the pf.PFQueue class:
PFQueue instances have the following attributes:
ServiceCurve objects allow you to assign the target, minimum and maximum bandwidth to a queue:
ServiceCurve instances have the following attributes:
FlowQueue objects allow you to tweak how multiple connections, assigned to the same queue, share the queue bandwidth.
FlowQueue instances have the following attributes:
PFQueue instances have the following attributes:
When adding queues to Packet Filter, please keep in mind that queues are arranged in a hierarchical manner (i.e. in a inverted-tree structure); therefore, you need to create an additional (root) queue that will be parent for the other queues: pfctl(8) manages this automatically by creating a parent queue named "root_ifname", so you may want to stick to the same naming convention.
For child queues, the parent attribute (i.e. the name of their parent queue) must be explicitly set, for PF to correctly build the queue tree; also note that the hierarchy can be further expanded by defining queues within queues.
# Enable queueing on the external interface to control incoming traffic. ifname = "em0" root = "root_" + ifname MB = 10**6 # Let's create the queues as a list: # queue std on em0 bandwidth 100M # queue ssh parent std bandwidth 10M burst 90M for 100ms # queue mail parent std bandwidth 10M, min 5M, max 25M # queue http parent std bandwidth 80M default queues = [pf.PFQueue(qname=root, ifname=ifname, linkshare=pf.ServiceCurve(bandwidth=100*MB), flags==pf.PFQS_ROOTCLASS), # Root queue pf.PFQueue(qname="std", parent=root, ifname=ifname, linkshare=pf.ServiceCurve(bandwidth=100*MB)), pf.PFQueue(qname="ssh", parent="std", ifname=ifname, linkshare=pf.ServiceCurve(10*MB, 90*MB, 100)), pf.PFQueue(qname="mail", parent="std", ifname=ifname, linkshare=pf.ServiceCurve(bandwidth=10*MB), realtime=pf.ServiceCurve(bandwidth=5*MB), upperlimit=pf.ServiceCurve(bandwidth=25*MB)), pf.PFQueue(qname="http", parent="std", ifname=ifname, linkshare=pf.ServiceCurve(bandwidth=80*MB), flags=pf.PFQS_DEFAULT)] # Load the queues on the system filter = pf.PacketFilter() filter.load_queues(*queues)