This script configures HFSC-based traffic shaping on OpenWrt to optimize latency-sensitive traffic (e.g., gaming), with special handling for DSCP marking and class-based queuing.
- Upload/download shaping using
tcand HFSC - DSCP marking support (via optional
nftables) pfifoqueue for game traffic- Class separation: real-time (gaming), default traffic
- Works with PPPoE over bridged VLAN from ISP
You can install the required packages via SSH with:
opkg update
opkg install tc kmod-sched kmod-sched-core kmod-sched-red kmod-ifb ip-full nftablesEdit /etc/hfsc-qos.sh to fit your network. Key parameters:
WAN="pppoe-wan" # WAN interface name
LAN="br-lan" # LAN bridge interface
UPRATE=95000 # Upload speed in kbit (95% of 100Mbps)
DOWNRATE=95000 # Download speed in kbit
GAMEUP=18500 # Reserved upload for gaming
GAMEDOWN=18500 # Reserved download for gaming
gameqdisc="pfifo" # Queue type for gaming (pfifo, fq_codel, etc.)
OH=40 # Overhead in bytes (for PPPoE + VLAN)
MPU=64 # Minimum packet unit- Place Script
cp hfsc-qos.sh /etc/hfsc-qos.sh
chmod +x /etc/hfsc-qos.sh- Init Script
Create /etc/init.d/hfsc-qos with the following content:
#!/bin/sh /etc/rc.common
START=95
STOP=15
start() {
logger -t hfsc-qos "Starting HFSC QoS..."
/etc/hfsc-qos.sh
}
stop() {
logger -t hfsc-qos "Stopping HFSC QoS..."
tc qdisc del dev pppoe-wan root 2>/dev/null
tc qdisc del dev br-lan root 2>/dev/null
}Make it executable:
chmod +x /etc/init.d/hfsc-qos/etc/init.d/hfsc-qos enable
/etc/init.d/hfsc-qos startYou can also use:
/etc/init.d/hfsc-qos restart
/etc/init.d/hfsc-qos stopRun:
tc -s qdisc show dev pppoe-wan
tc -s qdisc show dev br-lanLook for packet counters, drops, and class stats to verify shaping is working.
Add DSCP tagging to gaming packets by including rules in your nftables config. This integrates with /usr/share/nftables.d/ruleset-post/dscptag.nft.
Ensure it is fetched or created and included in your firewall.
If you're using tc, nftables, and pppoe, this script gives you a solid starting point for low-latency, class-based QoS.
Test your latency under load with:
ping -i 0.2 8.8.8.8/etc/hfsc-qos.sh— Main script/etc/init.d/hfsc-qos— Startup/init control script
cat << 'EOF' > /etc/hfsc-qos.sh
#!/bin/sh
# Interface definitions
WAN="pppoe-wan"
LAN="br-lan"
# Bandwidth configuration in kbit
UPRATE=95000
DOWNRATE=95000
GAMEUP=18500
GAMEDOWN=18500
# Qdisc options
gameqdisc="pfifo" # Options: pfifo, fq_codel, etc.
OH=40 # PPPoE + VLAN overhead
MPU=64 # Minimum packet unit
# Load IFB module
modprobe ifb
ip link add ifb0 type ifb 2>/dev/null
ip link set dev ifb0 up
# Reset Qdisc
tc qdisc del dev $WAN root 2>/dev/null
tc qdisc del dev ifb0 root 2>/dev/null
# Ingress shaping
tc qdisc add dev $WAN handle ffff: ingress
tc filter add dev $WAN parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
# Egress (upload) HFSC setup
tc qdisc add dev $WAN root handle 1: hfsc default 20
tc class add dev $WAN parent 1: classid 1:1 hfsc sc rate ${UPRATE}kbit ul rate ${UPRATE}kbit
# Gaming class - upload
tc class add dev $WAN parent 1:1 classid 1:10 hfsc rt m1 ${GAMEUP}kbit d 25ms m2 ${GAMEUP}kbit
tc qdisc add dev $WAN parent 1:10 handle 10: $gameqdisc
# Default class - upload
tc class add dev $WAN parent 1:1 classid 1:20 hfsc sc rate $((UPRATE - GAMEUP))kbit ul rate $((UPRATE - GAMEUP))kbit
tc qdisc add dev $WAN parent 1:20 handle 20: fq_codel
# Ingress (download) HFSC setup
tc qdisc add dev ifb0 root handle 1: hfsc default 20
tc class add dev ifb0 parent 1: classid 1:1 hfsc sc rate ${DOWNRATE}kbit ul rate ${DOWNRATE}kbit
# Gaming class - download
tc class add dev ifb0 parent 1:1 classid 1:10 hfsc rt m1 ${GAMEDOWN}kbit d 25ms m2 ${GAMEDOWN}kbit
tc qdisc add dev ifb0 parent 1:10 handle 10: $gameqdisc
# Default class - download
tc class add dev ifb0 parent 1:1 classid 1:20 hfsc sc rate $((DOWNRATE - GAMEDOWN))kbit ul rate $((DOWNRATE - GAMEDOWN))kbit
tc qdisc add dev ifb0 parent 1:20 handle 20: fq_codel
# DSCP matching (optional, adjust as needed)
tc filter add dev $WAN protocol ip parent 1: prio 1 u32 match ip dsfield 0x2e 0xff flowid 1:10
tc filter add dev ifb0 protocol ip parent 1: prio 1 u32 match ip dsfield 0x2e 0xff flowid 1:10
EOF