Configure network traffic shaping with tc and HTB for bandwidth management and QoS

Intermediate 45 min Apr 03, 2026 14 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up hierarchical token bucket (HTB) traffic shaping with tc to control bandwidth allocation, prioritize network traffic, and implement quality of service policies for optimal network performance.

Prerequisites

  • Root or sudo access
  • Network interface with outbound connectivity
  • Basic understanding of networking concepts

What this solves

Network traffic shaping controls bandwidth usage and prioritizes critical applications by managing data flow rates. This tutorial shows you how to implement hierarchical token bucket (HTB) queueing with tc (traffic control) to create bandwidth limits, prioritize different types of traffic, and ensure quality of service for mission-critical applications.

Step-by-step configuration

Install traffic control utilities

Install the iproute2 package which contains tc and related networking tools.

sudo apt update
sudo apt install -y iproute2 tc
sudo dnf update -y
sudo dnf install -y iproute tc

Identify network interface

Find the network interface you want to apply traffic shaping to. This is typically your primary ethernet or wireless interface.

ip link show
ip addr show
Note: Replace eth0 with your actual interface name in all following commands. Common names include enp0s3, ens160, or wlan0.

Remove existing qdisc

Clear any existing queueing discipline on the interface before setting up HTB.

sudo tc qdisc del dev eth0 root 2>/dev/null || true
sudo tc qdisc show dev eth0

Create root HTB queueing discipline

Set up the root HTB qdisc with a total bandwidth limit. This example limits total bandwidth to 10 Mbps.

sudo tc qdisc add dev eth0 root handle 1: htb default 30
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 10mbit

Create traffic classes with different priorities

Define traffic classes for different priority levels. High priority gets 4 Mbps guaranteed, medium gets 3 Mbps, and low priority gets 3 Mbps.

# High priority class (guaranteed 4 Mbps, can burst to 6 Mbps)
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 4mbit ceil 6mbit prio 1

Medium priority class (guaranteed 3 Mbps, can burst to 8 Mbps)

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

Low priority class (guaranteed 3 Mbps, can use all available)

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

Add fair queueing to each class

Attach Stochastic Fair Queueing (SFQ) to each class to ensure fair bandwidth distribution among flows within each priority class.

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

Create traffic classification filters

Set up filters to classify traffic into different priority classes based on ports, protocols, or IP addresses.

# SSH traffic (port 22) - high priority
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip sport 22 0xffff flowid 1:10

HTTP/HTTPS traffic (ports 80, 443) - medium priority

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dport 80 0xffff flowid 1:20 sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dport 443 0xffff flowid 1:20 sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip sport 80 0xffff flowid 1:20 sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip sport 443 0xffff flowid 1:20

Bulk traffic (FTP, BitTorrent) - low priority

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dport 21 0xffff flowid 1:30 sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip dport 6881 0xffff flowid 1:30

Add DSCP-based classification

Configure filters to honor DSCP (Differentiated Services Code Point) markings for enterprise QoS compliance.

# EF (Expedited Forwarding) - highest priority
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip tos 0xb8 0xfc flowid 1:10

AF31 (Assured Forwarding 3,1) - medium priority

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

Default/Best Effort - low priority

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 u32 match ip tos 0x00 0xfc flowid 1:30

Create network-based rules

Set up filters to prioritize traffic from specific IP ranges or subnets.

# Prioritize traffic from management subnet (192.168.1.0/24)
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 192.168.1.0/24 flowid 1:10

Medium priority for internal network (10.0.0.0/8)

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip src 10.0.0.0/8 flowid 1:20

Configure ingress traffic shaping

Set up ingress filtering to control incoming traffic rates using the intermediate functional block (IFB) device.

# Load IFB module and create virtual interface
sudo modprobe ifb
sudo ip link add ifb0 type ifb
sudo ip link set dev ifb0 up

Redirect ingress traffic to IFB interface

sudo tc qdisc add dev eth0 handle ffff: ingress sudo tc filter add dev eth0 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0

Apply HTB shaping to IFB interface

sudo tc qdisc add dev ifb0 root handle 1: htb default 30 sudo tc class add dev ifb0 parent 1: classid 1:1 htb rate 8mbit sudo tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 3mbit ceil 5mbit prio 1 sudo tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit prio 2 sudo tc class add dev ifb0 parent 1:1 classid 1:30 htb rate 2mbit ceil 8mbit prio 3

Create persistent configuration script

Save your traffic shaping configuration in a script for easy reapplication after reboots.

#!/bin/bash

Traffic Shaping Configuration Script

Interface to apply shaping to

INTERFACE=eth0 TOTAL_BW=10mbit INGRESS_BW=8mbit

Clear existing qdiscs

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

Setup egress shaping

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

Priority classes

tc class add dev $INTERFACE parent 1:1 classid 1:10 htb rate 4mbit ceil 6mbit prio 1 tc class add dev $INTERFACE parent 1:1 classid 1:20 htb rate 3mbit ceil 8mbit prio 2 tc class add dev $INTERFACE parent 1:1 classid 1:30 htb rate 3mbit ceil 10mbit prio 3

Fair queueing

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

Traffic classification filters

tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip dport 22 0xffff flowid 1:10 tc filter add dev $INTERFACE protocol ip parent 1:0 prio 1 u32 match ip sport 22 0xffff flowid 1:10 tc filter add dev $INTERFACE protocol ip parent 1:0 prio 2 u32 match ip dport 80 0xffff flowid 1:20 tc filter add dev $INTERFACE protocol ip parent 1:0 prio 2 u32 match ip dport 443 0xffff flowid 1:20

Setup ingress shaping with IFB

modprobe ifb ip link add ifb0 type ifb 2>/dev/null || true ip link set dev ifb0 up tc qdisc add dev $INTERFACE handle ffff: ingress tc filter add dev $INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0 tc qdisc add dev ifb0 root handle 1: htb default 30 tc class add dev ifb0 parent 1: classid 1:1 htb rate $INGRESS_BW tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 3mbit ceil 5mbit prio 1 tc class add dev ifb0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit prio 2 tc class add dev ifb0 parent 1:1 classid 1:30 htb rate 2mbit ceil 8mbit prio 3 echo "Traffic shaping applied successfully"
sudo chmod 755 /usr/local/bin/setup-traffic-shaping.sh
sudo /usr/local/bin/setup-traffic-shaping.sh

Configure automatic startup

Create a systemd service to automatically apply traffic shaping rules on boot.

[Unit]
Description=Network Traffic Shaping
After=network.target
Wants=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-traffic-shaping.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable traffic-shaping.service
sudo systemctl start traffic-shaping.service

Monitor and troubleshoot traffic shaping

View current traffic shaping configuration

Use tc show commands to display the current queueing disciplines, classes, and filters.

# Show queueing disciplines
sudo tc qdisc show dev eth0

Show traffic classes

sudo tc class show dev eth0

Show filters

sudo tc filter show dev eth0

Show detailed statistics

sudo tc -s class show dev eth0

Monitor bandwidth usage in real-time

Create a monitoring script to track bandwidth usage across different traffic classes.

#!/bin/bash

INTERFACE=eth0

echo "Traffic Class Statistics for $INTERFACE"
echo "======================================="

while true; do
    clear
    echo "$(date)"
    echo ""
    echo "Class Statistics:"
    tc -s class show dev $INTERFACE | grep -E "(class htb|Sent|rate)"
    echo ""
    echo "Filter Statistics:"
    tc -s filter show dev $INTERFACE | head -20
    echo ""
    echo "Press Ctrl+C to exit"
    sleep 5
done
sudo chmod 755 /usr/local/bin/monitor-traffic.sh

Test bandwidth limiting

Use iperf3 to test bandwidth limits and verify that traffic shaping is working correctly.

sudo apt install -y iperf3
sudo dnf install -y iperf3
# On server (destination):
iperf3 -s

On client (source) - test different ports:

Test SSH traffic (should get high priority)

iperf3 -c server_ip -p 22 -t 30

Test HTTP traffic (should get medium priority)

iperf3 -c server_ip -p 80 -t 30

Verify your setup

# Check if traffic shaping is active
sudo tc qdisc show dev eth0

Verify HTB classes are configured

sudo tc class show dev eth0 | grep htb

Check filter rules

sudo tc filter show dev eth0

Monitor real-time statistics

sudo tc -s class show dev eth0

Verify service is running

sudo systemctl status traffic-shaping.service

Test with actual traffic

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

Advanced QoS policies

Configure application-specific shaping

Set up traffic shaping for specific applications using iptables MARK targets and tc filters.

# Mark packets from specific applications
sudo iptables -t mangle -A OUTPUT -p tcp --dport 3306 -j MARK --set-mark 10  # MySQL
sudo iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 10  # PostgreSQL
sudo iptables -t mangle -A OUTPUT -p tcp --dport 25 -j MARK --set-mark 30    # SMTP (low priority)

Create filters based on packet marks

sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 10 fw flowid 1:10 # High priority sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 handle 30 fw flowid 1:30 # Low priority

Implement time-based QoS policies

Create a script to adjust bandwidth allocation based on time of day for business hours optimization.

#!/bin/bash

INTERFACE=eth0
HOUR=$(date +%H)

Clear existing classes

tc class del dev $INTERFACE classid 1:10 2>/dev/null || true tc class del dev $INTERFACE classid 1:20 2>/dev/null || true tc class del dev $INTERFACE classid 1:30 2>/dev/null || true if [ $HOUR -ge 9 ] && [ $HOUR -le 17 ]; then # Business hours: prioritize work traffic tc class add dev $INTERFACE parent 1:1 classid 1:10 htb rate 6mbit ceil 8mbit prio 1 tc class add dev $INTERFACE parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit prio 2 tc class add dev $INTERFACE parent 1:1 classid 1:30 htb rate 1mbit ceil 4mbit prio 3 else # Off hours: more balanced allocation tc class add dev $INTERFACE parent 1:1 classid 1:10 htb rate 4mbit ceil 6mbit prio 1 tc class add dev $INTERFACE parent 1:1 classid 1:20 htb rate 3mbit ceil 7mbit prio 2 tc class add dev $INTERFACE parent 1:1 classid 1:30 htb rate 3mbit ceil 8mbit prio 3 fi echo "QoS policies updated for $(date)"
sudo chmod 755 /usr/local/bin/dynamic-qos.sh

Add to crontab to run every hour

echo "0 /usr/local/bin/dynamic-qos.sh" | sudo crontab -

Common issues

SymptomCauseFix
tc command not foundiproute2 package not installedsudo apt install iproute2 or sudo dnf install iproute
RTNETLINK answers: File existsQdisc already exists on interfacesudo tc qdisc del dev eth0 root then recreate
Traffic shaping not workingWrong interface name specifiedCheck with ip link show and update scripts
Ingress shaping failsIFB module not loadedsudo modprobe ifb and echo ifb >> /etc/modules
Rules lost after rebootNo persistence configuredEnable systemd service: sudo systemctl enable traffic-shaping.service
Filter rules not matchingIncorrect syntax or precedenceCheck with tc filter show dev eth0 and verify u32 match syntax
Bandwidth limits too restrictiveRate and ceil values too lowIncrease values and monitor with tc -s class show
High priority traffic throttledParent class rate limit reachedIncrease parent class rate or adjust child class allocation

Next steps

Automated install script

Run this to automate the entire setup

#traffic shaping #bandwidth management #htb queueing #tc linux #qos configuration

Need help?

Don't want to manage this yourself?

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

Talk to an engineer