OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
        • Load Balancing
          • Build Redundant Load-Balanced Gateways
          • Load Balance Services with NAT or DSR
          • Build an HA HTTPS Load Balancer
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Design Considerations
        • Configuration
          • Assumptions
          • Queues and Classification (single-file policy)
          • Optional: VLAN PCP marking with set prio
          • Optional: Shaping replies from a published service
        • Verification
        • Troubleshooting
        • See Also

        QoS and Traffic Shaping

        Synopsis #

        This chapter shows how to classify and shape traffic with PF queues to protect latency-sensitive flows and to manage bulk transfers. Queue configuration and assignment are defined in pf.conf(5) and managed at runtime with pfctl(8) . Live inspection uses systat(1) and targeted captures with tcpdump(8) . Use these patterns to provide predictable latency for interactive protocols while keeping link utilization high.

        Design Considerations #

        • Shape egress, not ingress. Shaping controls the traffic you transmit. You cannot directly slow down packets already arriving from the Internet; prefer egress shaping and ACK prioritization to influence remote senders.
        • Accuracy of link rates. Specify realistic bandwidths for the WAN interface (provider rate minus overhead). If the root queue allows borrowing up to the physical line rate, the default queue may saturate the link.
        • Simple classes win. Start with three classes: interactive/voice, default, and bulk. Expand only when you have measurements showing contention.
        • Queue assignment strategy. Use set queue on rules (often via match) to assign traffic to queues. Consider the two-queue form to prioritize TCP ACKs and lowdelay traffic.
        • Priority vs. queues. set prio selects interface priority queues (0–7) and also maps to VLAN PCP on vlan(4) . It does not shape by itself. Use it sparingly in addition to queueing when you need L2 markings.
        • Verification first. Enable counters, test with reproducible flows, and watch queue utilization under load. Keep a roll-back of the previous pf.conf.

        Configuration #

        The example below shapes outbound traffic on a single uplink. It prioritizes SSH interactivity and VoIP, keeps web browsing responsive, and deprioritizes bulk transfers. Adjust interface names, addresses, and rates to match your environment.

        Assumptions #

        • em0 — WAN (100 Mb/s contracted)
        • em1 — LAN (10.10.10.0/24)

        Queues and Classification (single-file policy) #

        Place this in /etc/pf.conf. The QUEUEING and set queue syntax are defined in pf.conf(5) .

        ## /etc/pf.conf — QoS with PF queues (example)
        
        set skip on lo
        
        # Interfaces
        wan     = "em0"
        lan     = "em1"
        lan_net = "10.10.10.0/24"
        
        # -------------------------
        # Queue tree on the WAN
        # -------------------------
        # Root queue at or slightly below line rate; avoid over-commit until measured.
        queue rootq on $wan bandwidth 95M max 95M
        
        # Realistic classes. Borrowing is implicit unless max bounds them.
        queue voice       parent rootq bandwidth 2M    min 1M
        queue web         parent rootq bandwidth 40M
          queue web_bulk  parent web   bandwidth 35M
          queue web_prio  parent web   bandwidth 5M    min 2M
        queue ssh         parent rootq bandwidth 5M
          queue ssh_bulk  parent ssh   bandwidth 3M
          queue ssh_prio  parent ssh   bandwidth 2M    min 1M
        queue defaultq    parent rootq bandwidth 38M   default
        queue bulk        parent rootq bandwidth 10M   max 20M
        
        # -------------------------
        # Base policy (tighten to your model)
        # -------------------------
        block all
        
        # Permit LAN to anywhere; classification follows in match rules below
        pass in on $lan from $lan_net to any keep state
        
        # Permit outbound from the firewall itself
        pass out on $wan proto { tcp udp icmp } to any keep state
        
        # -------------------------
        # Classification (sticky via match rules)
        # -------------------------
        
        # VoIP (SIP + RTP range example)
        match out on $wan proto udp from $lan_net to any port { 5060, 10000:20000 } \
            set queue voice
        
        # SSH: favor interactivity by assigning TCP ACKs and lowdelay to the second queue
        match out on $wan proto tcp from $lan_net to any port 22 \
            set queue (ssh_bulk, ssh_prio)
        
        # HTTPS: keep browsing responsive by prioritizing ACKs/lowdelay
        match out on $wan proto tcp from $lan_net to any port 443 \
            set queue (web_bulk, web_prio)
        
        # Bulk examples: backup, torrents, rsync (adjust as needed)
        match out on $wan proto { tcp udp } from $lan_net to any port { 873, 6881:6999 } \
            set queue bulk
        
        # Default: everything else lands in the default queue
        # (No explicit rule needed because 'default' is marked on the queue tree)
        

        Load and confirm:

        doas pfctl -f /etc/pf.conf
          # Atomic reload
        doas pfctl -vvsq
          # Inspect the queue tree, rates, and counters
        

        This example assumes the upstream routes the LAN prefix. If private clients need NAT, integrate the per-WAN NAT rule from the router guide and verify queue assignment against the translated packet path. Enable IPv4 forwarding for routed clients.

        Optional: VLAN PCP marking with set prio #

        If your upstream honors 802.1Q PCP, assign a higher interface priority for voice while retaining queueing control. This marks L2 frames and may aid upstream scheduling on enterprise links.

        ## Excerpt — add to classification if using VLAN PCP
        match out on $wan proto udp from $lan_net to any port { 5060, 10000:20000 } \
            set prio 6 set queue voice
        

        Optional: Shaping replies from a published service #

        When you publish a LAN service to the Internet, assign queues on the rule that creates the inbound service state so its replies inherit the queue selection.

        ## Excerpt — shape egress from a LAN web server
        web_svc = "10.10.10.50"
        
        # If you also use rdr on the WAN elsewhere, keep that configuration unchanged.
        # Queue assignment is carried by the service state to replies.
        pass in on $wan proto tcp to ($wan) port 443 \
            rdr-to $web_svc \
            set queue (web_bulk, web_prio)
        

        Verification #

        • Queue usage and limits with pfctl(8) :
        doas pfctl -vvsq
          # Verify the tree, min/max/burst, current/peak rates, and packet counters
        doas pfctl -vvsr | egrep 'set queue|set prio'
          # Confirm rule-to-queue mappings are loaded as intended
        
        • Live view with systat(1) :
        systat pf
          # Observe states and rule counters under load; keep an eye on the queues' counters via pfctl
        
        • On-the-wire sanity with tcpdump(8) :
        doas tcpdump -ni em0 port 22 or port 443 or udp and portrange 10000-20000
          # Confirm flows exist during your test and correlate with queue counters
        
        • Load generation. Use controlled transfers (for example, scp/rsync for bulk and an SSH session for interactivity) to demonstrate that keystrokes remain responsive while bulk traffic is active.

        Troubleshooting #

        • No effect on latency or throughput. Ensure you created a queue tree on the egress interface actually carrying the traffic and that set queue rules match in the correct direction (often match out on $wan). Verify with pfctl -vvsr and pfctl -vvsq.
        • “queue does not exist.” A set queue refers to a leaf queue name not present on the outgoing interface. Correct the queue name or ensure the queue is a leaf under the proper parent.
        • Default queue saturates. If latency-sensitive traffic still suffers, reduce bandwidth or max on default, or raise min for priority queues. Validate with repeatable tests.
        • Unintended borrowing. If a child queue grows beyond expectations, cap it with max or lower the parent’s bandwidth.
        • ACK starvation. Without the two-queue form, TCP ACKs may sit behind large packets. Use set queue (bulk, prio) for classes that benefit from responsive ACKs.
        • Layer-2 markings ignored. set prio maps to VLAN PCP, but upstream equipment may ignore it. Treat it as a hint, not enforcement.
        • Shaping the wrong traffic. Use tcpdump to validate selectors. A common error is matching on in on $wan instead of out on $wan for client egress.

        See Also #

        • Networking
        • OpenBGPD
        • Related: IPv6 at Scale
        • Related: Telemetry, Logging, and Flow Export
        Report a bug
        • Synopsis
        • Design Considerations
        • Configuration
          • Assumptions
          • Queues and Classification (single-file policy)
          • Optional: VLAN PCP marking with set prio
          • Optional: Shaping replies from a published service
        • Verification
        • Troubleshooting
        • See Also