Set up traffic shaping with iptables packet marking, HTB queueing discipline, and multi-interface QoS policies for bandwidth management and network performance optimization.
Prerequisites
- Root access to Linux server
- Multiple network interfaces
- Basic understanding of iptables and networking
What this solves
This tutorial shows you how to configure Quality of Service (QoS) with iptables packet marking and traffic control (tc) to prioritize network traffic across multiple interfaces. You'll use fwmark to tag packets in iptables, then apply Hierarchical Token Bucket (HTB) queueing to shape bandwidth based on those marks. This is essential when you need to guarantee bandwidth for critical services while limiting less important traffic.
Step-by-step configuration
Install traffic control tools
Install the necessary packages for advanced traffic shaping and QoS management.
sudo apt update
sudo apt install -y iproute2 iptables-persistent netfilter-persistent
Configure network interfaces
Set up your network interfaces with proper IP addresses. We'll use eth0 for internal traffic and eth1 for external connections.
sudo ip addr add 192.168.1.10/24 dev eth0
sudo ip addr add 203.0.113.10/24 dev eth1
sudo ip link set eth0 up
sudo ip link set eth1 up
Create iptables mangle rules with fwmark
Set up packet marking rules to classify traffic by service type, source, and destination. These marks will be used by tc for traffic shaping.
# Clear existing mangle rules
sudo iptables -t mangle -F
sudo iptables -t mangle -X
Mark SSH traffic as high priority (mark 1)
sudo iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
sudo iptables -t mangle -A INPUT -p tcp --sport 22 -j MARK --set-mark 1
Mark HTTP/HTTPS traffic as medium priority (mark 2)
sudo iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 2
sudo iptables -t mangle -A OUTPUT -p tcp --dport 443 -j MARK --set-mark 2
sudo iptables -t mangle -A INPUT -p tcp --sport 80 -j MARK --set-mark 2
sudo iptables -t mangle -A INPUT -p tcp --sport 443 -j MARK --set-mark 2
Mark database traffic as high priority (mark 3)
sudo iptables -t mangle -A OUTPUT -p tcp --dport 3306 -j MARK --set-mark 3
sudo iptables -t mangle -A OUTPUT -p tcp --dport 5432 -j MARK --set-mark 3
sudo iptables -t mangle -A INPUT -p tcp --sport 3306 -j MARK --set-mark 3
sudo iptables -t mangle -A INPUT -p tcp --sport 5432 -j MARK --set-mark 3
Mark bulk transfer traffic as low priority (mark 4)
sudo iptables -t mangle -A OUTPUT -p tcp --dport 21 -j MARK --set-mark 4
sudo iptables -t mangle -A OUTPUT -p tcp --dport 20 -j MARK --set-mark 4
sudo iptables -t mangle -A INPUT -p tcp --sport 21 -j MARK --set-mark 4
sudo iptables -t mangle -A INPUT -p tcp --sport 20 -j MARK --set-mark 4
Set up HTB root qdisc on primary interface
Configure the Hierarchical Token Bucket queueing discipline on your primary interface (eth0) with a total bandwidth limit.
# Remove existing qdisc
sudo tc qdisc del dev eth0 root 2>/dev/null || true
Create HTB root qdisc with 100Mbit total bandwidth
sudo tc qdisc add dev eth0 root handle 1: htb default 40
Create root class with total bandwidth
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
Configure HTB classes for different priorities
Create HTB classes that correspond to your iptables marks, with guaranteed and maximum bandwidth allocations.
# High priority class for SSH and database (mark 1 and 3) - 40% guaranteed, can use up to 80%
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 80mbit prio 1
Medium priority class for HTTP/HTTPS (mark 2) - 30% guaranteed, can use up to 60%
sudo tc class add dev eth0 parent 1:1 classid 1:20 htb rate 30mbit ceil 60mbit prio 2
Low priority class for bulk transfers (mark 4) - 10% guaranteed, can use up to 40%
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 10mbit ceil 40mbit prio 3
Default class for unmarked traffic - 20% guaranteed, can use up to 50%
sudo tc class add dev eth0 parent 1:1 classid 1:40 htb rate 20mbit ceil 50mbit prio 4
Add queueing disciplines to leaf classes
Attach Stochastic Fair Queueing (SFQ) to each HTB class to ensure fair distribution among flows within each 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
Add SFQ to default class
sudo tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10
Create tc filters based on fwmark
Set up traffic control filters that direct packets to appropriate HTB classes based on their iptables fwmark values.
# Filter for SSH traffic (mark 1) -> high priority class
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 1 fw flowid 1:10
Filter for HTTP/HTTPS traffic (mark 2) -> medium priority class
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20
Filter for database traffic (mark 3) -> high priority class
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 3 fw flowid 1:10
Filter for bulk transfer traffic (mark 4) -> low priority class
sudo tc filter add dev eth0 protocol ip parent 1:0 prio 3 handle 4 fw flowid 1:30
Configure QoS on secondary interface
Set up similar traffic shaping on your secondary interface (eth1) with different bandwidth allocations.
# Remove existing qdisc from eth1
sudo tc qdisc del dev eth1 root 2>/dev/null || true
Create HTB root qdisc with 50Mbit total bandwidth for external interface
sudo tc qdisc add dev eth1 root handle 2: htb default 240
Create root class
sudo tc class add dev eth1 parent 2: classid 2:1 htb rate 50mbit
High priority class - 20Mbit guaranteed, 40Mbit max
sudo tc class add dev eth1 parent 2:1 classid 2:10 htb rate 20mbit ceil 40mbit prio 1
Medium priority class - 15Mbit guaranteed, 30Mbit max
sudo tc class add dev eth1 parent 2:1 classid 2:20 htb rate 15mbit ceil 30mbit prio 2
Low priority class - 5Mbit guaranteed, 20Mbit max
sudo tc class add dev eth1 parent 2:1 classid 2:30 htb rate 5mbit ceil 20mbit prio 3
Default class - 10Mbit guaranteed, 25Mbit max
sudo tc class add dev eth1 parent 2:1 classid 2:40 htb rate 10mbit ceil 25mbit prio 4
Add SFQ and filters to secondary interface
Complete the QoS setup on eth1 with fair queueing and fwmark-based filters.
# Add SFQ to all classes on eth1
sudo tc qdisc add dev eth1 parent 2:10 handle 210: sfq perturb 10
sudo tc qdisc add dev eth1 parent 2:20 handle 220: sfq perturb 10
sudo tc qdisc add dev eth1 parent 2:30 handle 230: sfq perturb 10
sudo tc qdisc add dev eth1 parent 2:40 handle 240: sfq perturb 10
Add filters based on fwmark
sudo tc filter add dev eth1 protocol ip parent 2:0 prio 1 handle 1 fw flowid 2:10
sudo tc filter add dev eth1 protocol ip parent 2:0 prio 2 handle 2 fw flowid 2:20
sudo tc filter add dev eth1 protocol ip parent 2:0 prio 1 handle 3 fw flowid 2:10
sudo tc filter add dev eth1 protocol ip parent 2:0 prio 3 handle 4 fw flowid 2:30
Create advanced marking rules for subnet-based QoS
Add more sophisticated iptables rules that classify traffic based on source and destination subnets for better traffic management.
# Mark internal management traffic as high priority
sudo iptables -t mangle -A OUTPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j MARK --set-mark 1
sudo iptables -t mangle -A INPUT -s 192.168.1.0/24 -d 192.168.1.0/24 -j MARK --set-mark 1
Mark traffic to/from DMZ as medium priority
sudo iptables -t mangle -A OUTPUT -s 192.168.2.0/24 -j MARK --set-mark 2
sudo iptables -t mangle -A OUTPUT -d 192.168.2.0/24 -j MARK --set-mark 2
sudo iptables -t mangle -A INPUT -s 192.168.2.0/24 -j MARK --set-mark 2
Mark guest network traffic as low priority
sudo iptables -t mangle -A OUTPUT -s 192.168.3.0/24 -j MARK --set-mark 4
sudo iptables -t mangle -A OUTPUT -d 192.168.3.0/24 -j MARK --set-mark 4
sudo iptables -t mangle -A INPUT -s 192.168.3.0/24 -j MARK --set-mark 4
Mark traffic based on packet size for bulk transfers
sudo iptables -t mangle -A OUTPUT -m length --length 1000:65535 -j MARK --set-mark 4
sudo iptables -t mangle -A INPUT -m length --length 1000:65535 -j MARK --set-mark 4
Save configuration for persistence
Save your iptables rules and create systemd service for tc rules to ensure they persist after reboot.
sudo netfilter-persistent save
sudo systemctl enable netfilter-persistent
[Unit]
Description=QoS Traffic Control Setup
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/setup-qos.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Create QoS setup script
Create a script to automatically configure tc rules on system startup.
#!/bin/bash
Setup QoS on eth0
tc qdisc del dev eth0 root 2>/dev/null || true
tc qdisc add dev eth0 root handle 1: htb default 40
tc class add dev eth0 parent 1: classid 1:1 htb rate 100mbit
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 40mbit ceil 80mbit prio 1
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 30mbit ceil 60mbit prio 2
tc class add dev eth0 parent 1:1 classid 1:30 htb rate 10mbit ceil 40mbit prio 3
tc class add dev eth0 parent 1:1 classid 1:40 htb rate 20mbit ceil 50mbit prio 4
Add SFQ
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10
Add filters
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 1 fw flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 2 handle 2 fw flowid 1:20
tc filter add dev eth0 protocol ip parent 1:0 prio 1 handle 3 fw flowid 1:10
tc filter add dev eth0 protocol ip parent 1:0 prio 3 handle 4 fw flowid 1:30
Setup QoS on eth1
tc qdisc del dev eth1 root 2>/dev/null || true
tc qdisc add dev eth1 root handle 2: htb default 240
tc class add dev eth1 parent 2: classid 2:1 htb rate 50mbit
tc class add dev eth1 parent 2:1 classid 2:10 htb rate 20mbit ceil 40mbit prio 1
tc class add dev eth1 parent 2:1 classid 2:20 htb rate 15mbit ceil 30mbit prio 2
tc class add dev eth1 parent 2:1 classid 2:30 htb rate 5mbit ceil 20mbit prio 3
tc class add dev eth1 parent 2:1 classid 2:40 htb rate 10mbit ceil 25mbit prio 4
Add SFQ
tc qdisc add dev eth1 parent 2:10 handle 210: sfq perturb 10
tc qdisc add dev eth1 parent 2:20 handle 220: sfq perturb 10
tc qdisc add dev eth1 parent 2:30 handle 230: sfq perturb 10
tc qdisc add dev eth1 parent 2:40 handle 240: sfq perturb 10
Add filters
tc filter add dev eth1 protocol ip parent 2:0 prio 1 handle 1 fw flowid 2:10
tc filter add dev eth1 protocol ip parent 2:0 prio 2 handle 2 fw flowid 2:20
tc filter add dev eth1 protocol ip parent 2:0 prio 1 handle 3 fw flowid 2:10
tc filter add dev eth1 protocol ip parent 2:0 prio 3 handle 4 fw flowid 2:30
sudo chmod +x /usr/local/bin/setup-qos.sh
sudo systemctl enable qos-setup.service
sudo systemctl start qos-setup.service
Monitor QoS performance
Set up monitoring to track QoS effectiveness and bandwidth utilization across your interfaces.
#!/bin/bash
echo "=== QoS Statistics for eth0 ==="
tc -s class show dev eth0
echo -e "\n=== QoS Statistics for eth1 ==="
tc -s class show dev eth1
echo -e "\n=== iptables Packet Counters ==="
iptables -t mangle -L -v -n
echo -e "\n=== Interface Statistics ==="
ip -s link show eth0
ip -s link show eth1
sudo chmod +x /usr/local/bin/qos-monitor.sh
Verify your setup
Check that your QoS configuration is working correctly and traffic is being classified properly.
# View current tc configuration
sudo tc qdisc show
sudo tc class show dev eth0
sudo tc filter show dev eth0
Check iptables mangle rules
sudo iptables -t mangle -L -v -n
Monitor real-time traffic classification
sudo /usr/local/bin/qos-monitor.sh
Test bandwidth limits with iperf3 (if available)
iperf3 -c example.com -p 80 -t 10
You can also monitor QoS effectiveness by examining the packet and byte counters:
# Watch real-time statistics
watch -n 2 'tc -s class show dev eth0'
Check specific class statistics
tc -s class show dev eth0 classid 1:10
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Traffic not being shaped | fwmark not set or filters missing | Check iptables rules with iptables -t mangle -L -v |
| HTB classes not working | Incorrect parent-child relationships | Verify class hierarchy with tc class show dev ethX |
| No bandwidth limiting | Default class not configured | Ensure HTB has default parameter set |
| Filters not matching | Wrong handle values in filters | Match filter handles to iptables marks exactly |
| Configuration lost after reboot | Rules not persisted | Enable systemd service: systemctl enable qos-setup |
| High latency on priority traffic | SFQ not attached to classes | Add SFQ qdisc to each HTB leaf class |
Next steps
- Configure advanced iptables firewall rules with logging and DDoS protection
- Set up Linux network traffic shaping with tc and QoS for bandwidth management
- Monitor network performance with Prometheus and Grafana dashboards
- Install and configure ntopng for comprehensive network monitoring
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Advanced iptables QoS with fwmark and multiple interfaces setup script
# Production-quality installer for traffic shaping and bandwidth management
readonly SCRIPT_NAME=$(basename "$0")
readonly TOTAL_STEPS=8
# Color definitions
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly NC='\033[0m' # No Color
# Default configuration
DEFAULT_INTERNAL_IFACE="eth0"
DEFAULT_EXTERNAL_IFACE="eth1"
DEFAULT_INTERNAL_IP="192.168.1.10/24"
DEFAULT_EXTERNAL_IP="203.0.113.10/24"
DEFAULT_BANDWIDTH="100mbit"
# Parse arguments
INTERNAL_IFACE="${1:-$DEFAULT_INTERNAL_IFACE}"
EXTERNAL_IFACE="${2:-$DEFAULT_EXTERNAL_IFACE}"
INTERNAL_IP="${3:-$DEFAULT_INTERNAL_IP}"
EXTERNAL_IP="${4:-$DEFAULT_EXTERNAL_IP}"
BANDWIDTH="${5:-$DEFAULT_BANDWIDTH}"
usage() {
echo "Usage: $SCRIPT_NAME [internal_iface] [external_iface] [internal_ip/cidr] [external_ip/cidr] [bandwidth]"
echo "Example: $SCRIPT_NAME eth0 eth1 192.168.1.10/24 203.0.113.10/24 100mbit"
echo "Defaults: $DEFAULT_INTERNAL_IFACE $DEFAULT_EXTERNAL_IFACE $DEFAULT_INTERNAL_IP $DEFAULT_EXTERNAL_IP $DEFAULT_BANDWIDTH"
exit 1
}
log() {
echo -e "${GREEN}[INFO]${NC} $*"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $*"
}
error() {
echo -e "${RED}[ERROR]${NC} $*" >&2
exit 1
}
cleanup() {
warn "Script failed. Cleaning up..."
tc qdisc del dev "$INTERNAL_IFACE" root 2>/dev/null || true
tc qdisc del dev "$EXTERNAL_IFACE" root 2>/dev/null || true
iptables -t mangle -F 2>/dev/null || true
}
trap cleanup ERR
check_root() {
if [[ $EUID -ne 0 ]]; then
error "This script must be run as root or with sudo"
fi
}
detect_distro() {
if [[ ! -f /etc/os-release ]]; then
error "Cannot detect distribution: /etc/os-release not found"
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update -qq"
PKG_INSTALL="apt install -y"
IPTABLES_PERSISTENT="iptables-persistent netfilter-persistent"
TC_PACKAGE="iproute2"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update -q || true"
PKG_INSTALL="dnf install -y"
IPTABLES_PERSISTENT="iptables-services"
TC_PACKAGE="iproute-tc"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update -q || true"
PKG_INSTALL="yum install -y"
IPTABLES_PERSISTENT="iptables-services"
TC_PACKAGE="iproute-tc"
;;
*)
error "Unsupported distribution: $ID"
;;
esac
}
install_packages() {
echo "[1/$TOTAL_STEPS] Installing traffic control tools and dependencies..."
log "Updating package cache..."
$PKG_UPDATE
log "Installing required packages..."
$PKG_INSTALL $TC_PACKAGE iptables $IPTABLES_PERSISTENT
# Enable services on RHEL-based systems
if [[ "$PKG_MGR" != "apt" ]]; then
systemctl enable iptables 2>/dev/null || true
fi
}
configure_interfaces() {
echo "[2/$TOTAL_STEPS] Configuring network interfaces..."
# Check if interfaces exist
if [[ ! -d "/sys/class/net/$INTERNAL_IFACE" ]]; then
error "Interface $INTERNAL_IFACE does not exist"
fi
if [[ ! -d "/sys/class/net/$EXTERNAL_IFACE" ]]; then
error "Interface $EXTERNAL_IFACE does not exist"
fi
log "Configuring $INTERNAL_IFACE with $INTERNAL_IP..."
ip addr flush dev "$INTERNAL_IFACE" 2>/dev/null || true
ip addr add "$INTERNAL_IP" dev "$INTERNAL_IFACE"
ip link set "$INTERNAL_IFACE" up
log "Configuring $EXTERNAL_IFACE with $EXTERNAL_IP..."
ip addr flush dev "$EXTERNAL_IFACE" 2>/dev/null || true
ip addr add "$EXTERNAL_IP" dev "$EXTERNAL_IFACE"
ip link set "$EXTERNAL_IFACE" up
}
setup_iptables_marks() {
echo "[3/$TOTAL_STEPS] Creating iptables mangle rules with fwmark..."
log "Clearing existing mangle rules..."
iptables -t mangle -F
iptables -t mangle -X 2>/dev/null || true
log "Setting up packet marking rules..."
# SSH traffic - high priority (mark 1)
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
iptables -t mangle -A INPUT -p tcp --sport 22 -j MARK --set-mark 1
# HTTP/HTTPS traffic - medium priority (mark 2)
iptables -t mangle -A OUTPUT -p tcp -m multiport --dports 80,443 -j MARK --set-mark 2
iptables -t mangle -A INPUT -p tcp -m multiport --sports 80,443 -j MARK --set-mark 2
# Database traffic - high priority (mark 3)
iptables -t mangle -A OUTPUT -p tcp -m multiport --dports 3306,5432 -j MARK --set-mark 3
iptables -t mangle -A INPUT -p tcp -m multiport --sports 3306,5432 -j MARK --set-mark 3
# FTP/bulk transfer - low priority (mark 4)
iptables -t mangle -A OUTPUT -p tcp -m multiport --dports 20,21 -j MARK --set-mark 4
iptables -t mangle -A INPUT -p tcp -m multiport --sports 20,21 -j MARK --set-mark 4
}
setup_htb_qdisc() {
echo "[4/$TOTAL_STEPS] Setting up HTB root qdisc on $INTERNAL_IFACE..."
# Remove existing qdisc
tc qdisc del dev "$INTERNAL_IFACE" root 2>/dev/null || true
log "Creating HTB root qdisc with $BANDWIDTH total bandwidth..."
tc qdisc add dev "$INTERNAL_IFACE" root handle 1: htb default 40
tc class add dev "$INTERNAL_IFACE" parent 1: classid 1:1 htb rate "$BANDWIDTH"
}
configure_htb_classes() {
echo "[5/$TOTAL_STEPS] Configuring HTB classes for different priorities..."
# Extract numeric value for calculations
RATE_NUM=$(echo "$BANDWIDTH" | sed 's/[^0-9]//g')
RATE_UNIT=$(echo "$BANDWIDTH" | sed 's/[0-9]//g')
# High priority (SSH, DB) - 40% guaranteed, 80% ceiling
HIGH_RATE=$((RATE_NUM * 40 / 100))${RATE_UNIT}
HIGH_CEIL=$((RATE_NUM * 80 / 100))${RATE_UNIT}
tc class add dev "$INTERNAL_IFACE" parent 1:1 classid 1:10 htb rate "$HIGH_RATE" ceil "$HIGH_CEIL" prio 1
# Medium priority (HTTP/HTTPS) - 30% guaranteed, 60% ceiling
MED_RATE=$((RATE_NUM * 30 / 100))${RATE_UNIT}
MED_CEIL=$((RATE_NUM * 60 / 100))${RATE_UNIT}
tc class add dev "$INTERNAL_IFACE" parent 1:1 classid 1:20 htb rate "$MED_RATE" ceil "$MED_CEIL" prio 2
# Low priority (bulk) - 10% guaranteed, 40% ceiling
LOW_RATE=$((RATE_NUM * 10 / 100))${RATE_UNIT}
LOW_CEIL=$((RATE_NUM * 40 / 100))${RATE_UNIT}
tc class add dev "$INTERNAL_IFACE" parent 1:1 classid 1:30 htb rate "$LOW_RATE" ceil "$LOW_CEIL" prio 3
# Default class - 20% guaranteed, 50% ceiling
DEF_RATE=$((RATE_NUM * 20 / 100))${RATE_UNIT}
DEF_CEIL=$((RATE_NUM * 50 / 100))${RATE_UNIT}
tc class add dev "$INTERNAL_IFACE" parent 1:1 classid 1:40 htb rate "$DEF_RATE" ceil "$DEF_CEIL" prio 4
log "HTB classes configured with bandwidth allocation"
}
setup_leaf_queues() {
echo "[6/$TOTAL_STEPS] Adding queueing disciplines to leaf classes..."
# Attach SFQ to each HTB class for fair queueing
tc qdisc add dev "$INTERNAL_IFACE" parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev "$INTERNAL_IFACE" parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev "$INTERNAL_IFACE" parent 1:30 handle 30: sfq perturb 10
tc qdisc add dev "$INTERNAL_IFACE" parent 1:40 handle 40: sfq perturb 10
log "SFQ disciplines attached to HTB classes"
}
setup_traffic_filters() {
echo "[7/$TOTAL_STEPS] Creating traffic filters based on fwmark..."
# Create filters to match fwmark and direct to appropriate classes
tc filter add dev "$INTERNAL_IFACE" parent 1: protocol ip prio 1 handle 1 fw flowid 1:10
tc filter add dev "$INTERNAL_IFACE" parent 1: protocol ip prio 2 handle 2 fw flowid 1:20
tc filter add dev "$INTERNAL_IFACE" parent 1: protocol ip prio 1 handle 3 fw flowid 1:10
tc filter add dev "$INTERNAL_IFACE" parent 1: protocol ip prio 3 handle 4 fw flowid 1:30
log "Traffic filters configured for fwmark-based classification"
}
save_configuration() {
echo "[8/$TOTAL_STEPS] Saving configuration..."
# Save iptables rules
if [[ "$PKG_MGR" == "apt" ]]; then
iptables-save > /etc/iptables/rules.v4
log "iptables rules saved to /etc/iptables/rules.v4"
else
iptables-save > /etc/sysconfig/iptables
log "iptables rules saved to /etc/sysconfig/iptables"
fi
# Create startup script for tc rules
cat > /usr/local/bin/qos-setup.sh << EOF
#!/bin/bash
# QoS Traffic Control Setup Script - Auto-generated
# Setup HTB qdisc and classes
tc qdisc del dev $INTERNAL_IFACE root 2>/dev/null || true
tc qdisc add dev $INTERNAL_IFACE root handle 1: htb default 40
tc class add dev $INTERNAL_IFACE parent 1: classid 1:1 htb rate $BANDWIDTH
# Create HTB classes
tc class add dev $INTERNAL_IFACE parent 1:1 classid 1:10 htb rate $HIGH_RATE ceil $HIGH_CEIL prio 1
tc class add dev $INTERNAL_IFACE parent 1:1 classid 1:20 htb rate $MED_RATE ceil $MED_CEIL prio 2
tc class add dev $INTERNAL_IFACE parent 1:1 classid 1:30 htb rate $LOW_RATE ceil $LOW_CEIL prio 3
tc class add dev $INTERNAL_IFACE parent 1:1 classid 1:40 htb rate $DEF_RATE ceil $DEF_CEIL prio 4
# Attach SFQ to leaf classes
tc qdisc add dev $INTERNAL_IFACE parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev $INTERNAL_IFACE parent 1:20 handle 20: sfq perturb 10
tc qdisc add dev $INTERNAL_IFACE parent 1:30 handle 30: sfq perturb 10
tc qdisc add dev $INTERNAL_IFACE parent 1:40 handle 40: sfq perturb 10
# Create filters
tc filter add dev $INTERNAL_IFACE parent 1: protocol ip prio 1 handle 1 fw flowid 1:10
tc filter add dev $INTERNAL_IFACE parent 1: protocol ip prio 2 handle 2 fw flowid 1:20
tc filter add dev $INTERNAL_IFACE parent 1: protocol ip prio 1 handle 3 fw flowid 1:10
tc filter add dev $INTERNAL_IFACE parent 1: protocol ip prio 3 handle 4 fw flowid 1:30
EOF
chmod 755 /usr/local/bin/qos-setup.sh
# Create systemd service for tc rules persistence
cat > /etc/systemd/system/qos-setup.service << EOF
[Unit]
Description=QoS Traffic Control Setup
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/qos-setup.sh
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable qos-setup.service
log "QoS configuration will persist across reboots"
}
verify_configuration() {
log "Verifying QoS configuration..."
# Check iptables mangle rules
if iptables -t mangle -L | grep -q "MARK"; then
log "✓ iptables mangle rules are active"
else
warn "⚠ iptables mangle rules not found"
fi
# Check tc configuration
if tc qdisc show dev "$
Review the script before running. Execute with: bash install.sh