How to Enable QoS (Quality of Service) with PF on FreeBSD Operating System

This article provides a step-by-step guide on how to enable QoS (Quality of Service) using PF (Packet Filter) on FreeBSD, a powerful and versatile open-source operating system.

Quality of Service (QoS) is a critical feature for network administrators and users who need to prioritize certain types of network traffic over others. Whether you’re managing a home network, a small business, or a large enterprise, QoS ensures that important traffic, such as VoIP calls or video conferencing, gets the bandwidth it needs, even during periods of high network congestion. FreeBSD, a powerful and versatile open-source operating system, provides robust tools for implementing QoS, one of which is the Packet Filter (PF). In this article, we will explore how to enable QoS using PF on FreeBSD.

Understanding QoS and PF

What is QoS?

Quality of Service (QoS) refers to the ability of a network to provide different priority levels to different applications, users, or data flows. This ensures that critical applications receive the necessary bandwidth and low latency, while less important traffic is deprioritized. QoS is particularly useful in environments where network resources are limited, and congestion is likely to occur.

What is PF?

PF (Packet Filter) is a powerful firewall and traffic shaping tool that is part of the FreeBSD operating system. Originally developed for OpenBSD, PF was ported to FreeBSD and has since become a popular choice for network administrators. PF provides a wide range of features, including stateful packet filtering, network address translation (NAT), and traffic shaping, which is essential for implementing QoS.

Prerequisites

Before diving into the configuration, ensure that you have the following:

  1. FreeBSD Installation: A working FreeBSD system with root access.

  2. PF Enabled: PF should be enabled and properly configured on your system. If you haven’t enabled PF yet, you can do so by adding the following lines to /etc/rc.conf:

    pf_enable="YES"
    pflog_enable="YES"
    

    Then, start PF with:

    service pf start
    
  3. Basic Networking Knowledge: Familiarity with networking concepts such as IP addresses, subnets, and ports will be helpful.

  4. Traffic Analysis: Identify the types of traffic you want to prioritize (e.g., VoIP, video streaming, gaming) and their respective ports or protocols.

Step 1: Define Traffic Classes

The first step in implementing QoS with PF is to define traffic classes. Traffic classes are categories that group similar types of traffic together. For example, you might create classes for VoIP, video streaming, web browsing, and file downloads.

In PF, traffic classes are defined using altq, which stands for “alternate queuing.” altq allows you to create queues for different types of traffic and assign priorities to them.

Here’s an example of how to define traffic classes in /etc/pf.conf:

altq on $ext_if cbq bandwidth 100Mb queue { voip, video, web, default }
queue voip bandwidth 20% cbq(default)
queue video bandwidth 30% cbq
queue web bandwidth 20% cbq
queue default bandwidth 30% cbq

In this example:

  • altq on $ext_if cbq bandwidth 100Mb enables altq on the external interface ($ext_if) with a total bandwidth of 100 Mbps using the Class-Based Queuing (CBQ) algorithm.
  • queue voip bandwidth 20% cbq(default) creates a queue named voip with 20% of the total bandwidth and marks it as the default queue.
  • queue video bandwidth 30% cbq creates a queue named video with 30% of the total bandwidth.
  • queue web bandwidth 20% cbq creates a queue named web with 20% of the total bandwidth.
  • queue default bandwidth 30% cbq creates a default queue for all other traffic with 30% of the total bandwidth.

Step 2: Create Filter Rules to Assign Traffic to Queues

Once you have defined your traffic classes, the next step is to create filter rules that assign traffic to the appropriate queues. This is done using the queue keyword in PF rules.

Here’s an example of how to assign traffic to the queues defined earlier:

pass in on $ext_if proto udp from any to any port 5060 queue voip  # SIP traffic
pass in on $ext_if proto udp from any to any port 10000:20000 queue voip  # RTP traffic (VoIP)
pass in on $ext_if proto tcp from any to any port 80 queue web  # HTTP traffic
pass in on $ext_if proto tcp from any to any port 443 queue web  # HTTPS traffic
pass in on $ext_if proto tcp from any to any port 1935 queue video  # RTMP traffic (video streaming)
pass in on $ext_if proto udp from any to any port 3478 queue video  # STUN traffic (video conferencing)
pass in on $ext_if proto udp from any to any port 33434:33534 queue default  # Default queue for other traffic

In this example:

  • SIP traffic (port 5060) and RTP traffic (ports 10000-20000) are assigned to the voip queue.
  • HTTP (port 80) and HTTPS (port 443) traffic are assigned to the web queue.
  • RTMP (port 1935) and STUN (port 3478) traffic are assigned to the video queue.
  • All other traffic is assigned to the default queue.

Step 3: Enable and Test the Configuration

After defining your traffic classes and filter rules, the next step is to enable the configuration and test it.

  1. Reload PF Configuration: To apply the changes, reload the PF configuration:

    pfctl -f /etc/pf.conf
    
  2. Check PF Status: Verify that PF is running and the new rules are in place:

    pfctl -s rules
    
  3. Monitor Traffic: Use tools like tcpdump or pfctl -vvsq to monitor traffic and ensure that it is being assigned to the correct queues.

  4. Test QoS: Generate different types of traffic (e.g., VoIP calls, video streaming, web browsing) and observe how the network behaves. Ensure that high-priority traffic (e.g., VoIP) is not being starved of bandwidth during periods of congestion.

Step 4: Fine-Tune and Optimize

QoS configuration is not a one-size-fits-all solution. Depending on your network’s specific needs, you may need to fine-tune your configuration. Here are some tips for optimization:

  1. Adjust Bandwidth Allocation: If you find that certain types of traffic are not getting enough bandwidth, adjust the percentages allocated to each queue.
  2. Add More Queues: If you have more types of traffic to prioritize, consider adding more queues.
  3. Use Different Queuing Disciplines: PF supports multiple queuing disciplines, such as CBQ, PRIQ, and HFSC. Experiment with different disciplines to see which one works best for your network.
  4. Monitor and Analyze: Continuously monitor your network’s performance and adjust your QoS settings as needed.

Conclusion

Implementing QoS with PF on FreeBSD is a powerful way to ensure that critical network traffic receives the priority it deserves. By defining traffic classes, creating filter rules, and fine-tuning your configuration, you can effectively manage network congestion and improve the overall performance of your network.

While the process may seem complex at first, the flexibility and control offered by PF make it a valuable tool for any network administrator. With careful planning and ongoing optimization, you can create a QoS setup that meets the unique needs of your network, ensuring a smooth and efficient experience for all users.

By following the steps outlined in this article, you should be well on your way to enabling QoS with PF on FreeBSD. Whether you’re managing a small home network or a large enterprise, the principles remain the same: prioritize what matters most, and let PF handle the rest.