Configure advanced iptables QoS with DSCP marking and traffic classification

Advanced 35 min Apr 07, 2026 65 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up Quality of Service (QoS) on Linux servers using iptables DSCP marking, HTB queuing, and traffic classification. This tutorial shows you how to prioritize network traffic, implement bandwidth limits, and ensure critical applications get the network resources they need for optimal performance.

Prerequisites

  • Root or sudo access
  • Basic understanding of networking concepts
  • Active network interface
  • iptables installed and configured

What this solves

Network congestion can severely impact application performance, especially for latency-sensitive services like VoIP, video conferencing, and real-time databases. This tutorial configures advanced Quality of Service (QoS) using iptables DSCP marking and Hierarchical Token Bucket (HTB) queuing to prioritize critical traffic, implement bandwidth limits, and ensure fair resource allocation across your network infrastructure.

Step-by-step configuration

Install traffic control utilities

Install the iproute2 package which provides the tc (traffic control) command for managing network queues and traffic shaping.

sudo apt update
sudo apt install -y iproute2 iptables-persistent netfilter-persistent
sudo systemctl enable netfilter-persistent
sudo dnf update -y
sudo dnf install -y iproute tc iptables-services
sudo systemctl enable iptables

Create HTB queuing discipline

Set up the HTB root queue with a total bandwidth limit and create priority classes for different types of traffic.

# Remove existing queues
sudo tc qdisc del dev eth0 root 2>/dev/null || true

Create root HTB queue with 100Mbps total bandwidth

sudo tc qdisc add dev eth0 root handle 1: htb default 30

Create root class with total bandwidth

sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit

High priority class (40% bandwidth, can burst to 80%)

sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 80mbit prio 1

Medium priority class (40% bandwidth, can burst to 60%)

sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 40mbit ceil 60mbit prio 2

Low priority class (20% bandwidth, can burst to 40%)

sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 20mbit ceil 40mbit prio 3

Add SFQ queuing to leaf classes

Attach Stochastic Fair Queuing (SFQ) to each class to ensure fair distribution among flows within the same priority level.

# Add SFQ to high priority class
sudo tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10

Add SFQ to medium priority class

sudo tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

Add SFQ to low priority class

sudo tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10

Configure iptables DSCP marking rules

Create iptables rules to mark different types of traffic with appropriate DSCP values for classification.

# Create DSCP marking chain
sudo iptables -t mangle -N QOS_MARKING

Jump to marking chain for all traffic

sudo iptables -t mangle -A OUTPUT -j QOS_MARKING sudo iptables -t mangle -A FORWARD -j QOS_MARKING

Mark VoIP traffic (SIP, RTP) - Expedited Forwarding (EF)

sudo iptables -t mangle -A QOS_MARKING -p udp --dport 5060 -j DSCP --set-dscp-class EF sudo iptables -t mangle -A QOS_MARKING -p udp --dport 10000:20000 -j DSCP --set-dscp-class EF

Mark video traffic - Assured Forwarding 41 (AF41)

sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 1935 -j DSCP --set-dscp-class AF41 sudo iptables -t mangle -A QOS_MARKING -p udp --dport 1935 -j DSCP --set-dscp-class AF41

Mark database traffic - Assured Forwarding 31 (AF31)

sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 3306 -j DSCP --set-dscp-class AF31 sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 5432 -j DSCP --set-dscp-class AF31

Mark web traffic - Assured Forwarding 21 (AF21)

sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 80 -j DSCP --set-dscp-class AF21 sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 443 -j DSCP --set-dscp-class AF21

Mark SSH traffic - Assured Forwarding 22 (AF22)

sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 22 -j DSCP --set-dscp-class AF22

Mark bulk transfer traffic - Best Effort (default)

sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 21 -j DSCP --set-dscp-class BE sudo iptables -t mangle -A QOS_MARKING -p tcp --dport 20 -j DSCP --set-dscp-class BE

Create traffic classification filters

Set up tc filters to classify packets based on their DSCP markings and direct them to appropriate HTB classes.

# Filter for high priority traffic (EF, AF41)
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip tos 0xb8 0xfc flowid 1:10
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip tos 0x88 0xfc flowid 1:10

Filter for medium priority traffic (AF31, AF22)

sudo tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip tos 0x68 0xfc flowid 1:20 sudo tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip tos 0x50 0xfc flowid 1:20

Filter for web traffic (AF21)

sudo tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip tos 0x48 0xfc flowid 1:20

Default filter for unmarked traffic (low priority)

sudo tc filter add dev eth0 parent 1: protocol ip prio 3 u32 match ip dst 0.0.0.0/0 flowid 1:30

Configure ingress traffic control

Set up ingress filtering to control incoming traffic rates and prevent network flooding.

# Add ingress qdisc
sudo tc qdisc add dev eth0 handle ffff: ingress

Limit total ingress rate to 80Mbps

sudo tc filter add dev eth0 parent ffff: protocol ip prio 1 u32 match u32 0 0 police rate 80mbit burst 10k drop flowid :1

Rate limit specific services

Limit HTTP/HTTPS to 50Mbps

sudo tc filter add dev eth0 parent ffff: protocol ip prio 2 u32 match ip sport 80 0xffff police rate 25mbit burst 5k drop sudo tc filter add dev eth0 parent ffff: protocol ip prio 2 u32 match ip sport 443 0xffff police rate 25mbit burst 5k drop

Create QoS monitoring script

Create a script to monitor QoS statistics and queue performance for ongoing optimization.

#!/bin/bash

echo "=== HTB Queue Statistics ==="
tc -s class show dev eth0

echo ""
echo "=== Filter Statistics ==="
tc -s filter show dev eth0

echo ""
echo "=== Ingress Statistics ==="
tc -s qdisc show dev eth0

echo ""
echo "=== DSCP Marking Rules ==="
iptables -t mangle -L QOS_MARKING -n -v

echo ""
echo "=== Network Interface Statistics ==="
cat /proc/net/dev | grep eth0

Make the monitoring script executable

Set proper permissions for the monitoring script and create a systemd timer for regular monitoring.

sudo chmod 755 /usr/local/bin/qos-monitor.sh

Test the monitoring script

sudo /usr/local/bin/qos-monitor.sh

Save iptables rules permanently

Ensure iptables rules persist across system reboots by saving them to the appropriate configuration files.

sudo netfilter-persistent save
sudo systemctl enable netfilter-persistent
sudo iptables-save > /etc/sysconfig/iptables
sudo systemctl enable iptables

Create QoS startup script

Create a systemd service to automatically configure traffic control rules at system startup.

[Unit]
Description=QoS Traffic Control Setup
After=network.target
Wants=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/qos-setup.sh
ExecStop=/usr/local/bin/qos-teardown.sh

[Install]
WantedBy=multi-user.target

Create QoS setup and teardown scripts

Create scripts to set up and tear down the QoS configuration for easy management.

#!/bin/bash

Interface to configure

INTERFACE="eth0" TOTAL_BW="100mbit"

Remove existing queues

tc qdisc del dev $INTERFACE root 2>/dev/null || true tc qdisc del dev $INTERFACE ingress 2>/dev/null || true

Create root HTB queue

tc qdisc add dev $INTERFACE root handle 1: htb default 30 tc class add dev $INTERFACE parent 1: classid 1:1 htb rate $TOTAL_BW

Create priority classes

tc class add dev $INTERFACE parent 1:1 classid 1:10 htb rate 40mbit ceil 80mbit prio 1 tc class add dev $INTERFACE parent 1:1 classid 1:20 htb rate 40mbit ceil 60mbit prio 2 tc class add dev $INTERFACE parent 1:1 classid 1:30 htb rate 20mbit ceil 40mbit prio 3

Add SFQ to leaf classes

tc qdisc add dev $INTERFACE parent 1:10 handle 10: sfq perturb 10 tc qdisc add dev $INTERFACE parent 1:20 handle 20: sfq perturb 10 tc qdisc add dev $INTERFACE parent 1:30 handle 30: sfq perturb 10

Add filters

tc filter add dev $INTERFACE parent 1: protocol ip prio 1 u32 match ip tos 0xb8 0xfc flowid 1:10 tc filter add dev $INTERFACE parent 1: protocol ip prio 1 u32 match ip tos 0x88 0xfc flowid 1:10 tc filter add dev $INTERFACE parent 1: protocol ip prio 2 u32 match ip tos 0x68 0xfc flowid 1:20 tc filter add dev $INTERFACE parent 1: protocol ip prio 2 u32 match ip tos 0x50 0xfc flowid 1:20 tc filter add dev $INTERFACE parent 1: protocol ip prio 2 u32 match ip tos 0x48 0xfc flowid 1:20 tc filter add dev $INTERFACE parent 1: protocol ip prio 3 u32 match ip dst 0.0.0.0/0 flowid 1:30

Configure ingress

tc qdisc add dev $INTERFACE handle ffff: ingress tc filter add dev $INTERFACE parent ffff: protocol ip prio 1 u32 match u32 0 0 police rate 80mbit burst 10k drop flowid :1 echo "QoS configuration applied successfully"

Create the teardown script

Create a script to cleanly remove all QoS configurations when needed.

#!/bin/bash

INTERFACE="eth0"

Remove all traffic control rules

tc qdisc del dev $INTERFACE root 2>/dev/null || true tc qdisc del dev $INTERFACE ingress 2>/dev/null || true echo "QoS configuration removed successfully"

Enable the QoS service

Make the scripts executable and enable the systemd service to start automatically.

sudo chmod +x /usr/local/bin/qos-setup.sh
sudo chmod +x /usr/local/bin/qos-teardown.sh

sudo systemctl enable qos-setup.service
sudo systemctl start qos-setup.service
sudo systemctl status qos-setup.service

Verify your setup

Test the QoS configuration to ensure traffic is being classified and shaped correctly.

# Check HTB classes and statistics
sudo tc -s class show dev eth0

Check filter rules

sudo tc -s filter show dev eth0

Verify iptables DSCP marking

sudo iptables -t mangle -L QOS_MARKING -n -v

Test traffic classification with iperf3 (if available)

iperf3 -c example.com -p 80 -t 10

Monitor real-time queue statistics

watch -n 1 'tc -s class show dev eth0'
Note: Replace eth0 with your actual network interface name. Use ip link show to list available interfaces.

Monitor and validate QoS performance

Set up continuous monitoring

Create a monitoring solution to track QoS performance and identify optimization opportunities.

# Create log directory for QoS metrics
sudo mkdir -p /var/log/qos

Create monitoring cron job

echo "/5 * root /usr/local/bin/qos-monitor.sh >> /var/log/qos/qos-stats.log 2>&1" | sudo tee -a /etc/crontab

Restart cron service

sudo systemctl restart cron || sudo systemctl restart crond

Configure DSCP validation script

Create a script to test and validate DSCP marking for different traffic types.

#!/bin/bash

Test DSCP marking for different protocols

echo "Testing DSCP marking..."

Simulate different traffic types and check DSCP values

echo "HTTP traffic should be marked AF21 (0x48):" tcpdump -i eth0 -c 5 "tcp port 80" -v 2>/dev/null | grep "tos" echo "SSH traffic should be marked AF22 (0x50):" tcpdump -i eth0 -c 5 "tcp port 22" -v 2>/dev/null | grep "tos" echo "Database traffic should be marked AF31 (0x68):" tcpdump -i eth0 -c 5 "tcp port 3306 or tcp port 5432" -v 2>/dev/null | grep "tos"

Make the test script executable

Set appropriate permissions for the DSCP validation script.

sudo chmod +x /usr/local/bin/test-dscp.sh

Common issues

Symptom Cause Fix
QoS rules not applied after reboot Scripts not enabled in systemd sudo systemctl enable qos-setup.service
Traffic not being classified Wrong interface name in scripts Update INTERFACE variable with ip link show
DSCP marking not working iptables rules not saved sudo netfilter-persistent save
High latency despite QoS Buffer bloat or incorrect bandwidth limits Reduce HTB queue lengths and adjust bandwidth values
No statistics showing in tc output No traffic matching filters Check filter rules with tc -s filter show dev eth0
Permission denied when running scripts Scripts not executable sudo chmod +x /usr/local/bin/qos-*.sh
Important: QoS is most effective when applied at network bottlenecks. Configure QoS on routers and gateways where traffic aggregation occurs for maximum impact.

Next steps

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle private cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.