QoSmate is a Quality of Service (QoS) solution for OpenWrt routers that aims to optimize network performance while allowing for controlled prioritization of specific traffic types. It uses nftables for packet classification and offers both CAKE (Common Applications Kept Enhanced) and HFSC (Hierarchical Fair Service Curve) queueing disciplines for traffic management. It uses tc-ctinfo to restore DSCP marks on ingress.
The project builds upon the amazing work of @dlakelan and his SimpleHFSCgamerscript, extending its capabilities and adding a user-friendly interface. QoSmate integrates concepts from various QoS systems, including SQM, DSCPCLASSIFY and cake-qos-simple to provide a comprehensive approach to traffic control.
Key aspects of QoSmate include
While QoSmate can benefit various types of network traffic, including gaming and other latency-sensitive applications, it is designed to improve overall network performance when configured properly.
Important Note: Effective QoS is about strategic prioritization, not blanket elevation of all traffic. QoSmate allows you to prioritize specific traffic types, but it's crucial to use this capability judiciously. Over-prioritization can negate the benefits of QoS, as elevating too much traffic essentially equates to no prioritization at all. Remember that for every packet given preferential treatment, others may experience increased delay or even drops. The goal is to create a balanced, efficient network environment, not to prioritize everything.
Before installing QoSmate, ensure that:
Install the QoSmate backend (which contains a main script/init script/hotplug and a config-file) with the following command:
wget -O /etc/init.d/qosmate https://raw.githubusercontent.com/hudra0/qosmate/main/etc/init.d/qosmate && chmod +x /etc/init.d/qosmate && wget -O /etc/qosmate.sh https://raw.githubusercontent.com/hudra0/qosmate/main/etc/qosmate.sh && chmod +x /etc/qosmate.sh && wget -O /etc/config/qosmate https://raw.githubusercontent.com/hudra0/qosmate/main/etc/config/qosmate
Install luci-app-qosmate with this command:
mkdir -p /www/luci-static/resources/view/qosmate /usr/share/luci/menu.d /usr/share/rpcd/acl.d /usr/libexec/rpcd && \
wget -O /www/luci-static/resources/view/qosmate/settings.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/settings.js && \
wget -O /www/luci-static/resources/view/qosmate/hfsc.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/hfsc.js && \
wget -O /www/luci-static/resources/view/qosmate/cake.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/cake.js && \
wget -O /www/luci-static/resources/view/qosmate/advanced.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/advanced.js && \
wget -O /www/luci-static/resources/view/qosmate/rules.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/rules.js && \
wget -O /www/luci-static/resources/view/qosmate/connections.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/connections.js && \
wget -O /www/luci-static/resources/view/qosmate/custom_rules.js https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/htdocs/luci-static/resources/view/custom_rules.js && \
wget -O /usr/share/luci/menu.d/luci-app-qosmate.json https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/root/usr/share/luci/menu.d/luci-app-qosmate.json && \
wget -O /usr/share/rpcd/acl.d/luci-app-qosmate.json https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/root/usr/share/rpcd/acl.d/luci-app-qosmate.json && \
wget -O /usr/libexec/rpcd/luci.qosmate https://raw.githubusercontent.com/hudra0/luci-app-qosmate/main/root/usr/libexec/rpcd/luci.qosmate && \
chmod +x /usr/libexec/rpcd/luci.qosmate && \
/etc/init.d/rpcd restart && \
/etc/init.d/uhttpd restart
/etc/init.d/qosmate start
For users preferring automatic configuration, QoSmate offers an Auto-setup function:
Note: Router-based speed tests may underestimate your actual connection speed. For more precise settings, run a speed test from a LAN device and manually input the results. The auto-setup provides a useful starting point, but manual fine-tuning may be necessary for optimal performance.
Config option | Description | Type | Default |
---|---|---|---|
enabled | Enables or disables QoSmate. Set to 1 to enable, 0 to disable. | boolean | 1 |
WAN | Specifies the WAN interface. This is crucial for applying QoS rules to the correct network interface. It's typically the interface connected to your ISP. | string | eth1 |
DOWNRATE | Download rate in kbps. Set this to about 80-90% of your actual download speed to allow for overhead and prevent bufferbloat. This creates a buffer that helps maintain low latency even when the connection is fully utilized. | integer | 90000 |
UPRATE | Upload rate in kbps. Set this to about 80-90% of your actual upload speed for the same reasons as DOWNRATE. | integer | 45000 |
ROOT_QDISC | Specifies the root queueing discipline. Options are 'hfsc' or 'cake' | enum (hfsc, cake) | hfsc |
Config option | Description | Type | Default |
---|---|---|---|
LINKTYPE | Specifies the link type. This affects how overhead is calculated. 'ethernet' is common for most connections, 'atm' for DSL, and 'DOCSIS' for cable internet. | enum (ethernet, atm, DOCSIS) | ethernet |
OH | Overhead in bytes. This accounts for layer 2 encapsulation overhead. Adjust based on your connection type. | integer | |
gameqdisc | Queueing discipline for game traffic. Options include 'pfifo ' 'bfifo' , 'fq_codel' , 'red' , and 'netem'. Each has different characteristics for managing realtime traffic. | enum (pfifo, bfifo fq_codel, red, netem) | pfifo |
GAMEUP | Upload bandwidth reserved for gaming in kbps. Formula ensures minimum bandwidth for games even on slower connections. | integer | (UPRATE*15/100+400) |
GAMEDOWN | Download bandwidth reserved for gaming in kbps. Similar to GAMEUP, but for download traffic. | integer | (DOWNRATE*15/100+400) |
nongameqdisc | Queueing discipline for non-realtime traffic. 'fq_codel' or 'cake'. | enum (fq_codel, cake) | fq_codel |
nongameqdiscoptions | Additional cake options when cake is set as the non-game qdisc. | string | "besteffort ack-filter" |
MAXDEL | Maximum delay in milliseconds. This sets an upper bound on queueing delay, helping to maintain responsiveness even under load. | integer | 24 |
PFIFOMIN | Minimum number of packets in the pfifo queue. | integer | 5 |
PACKETSIZE | Pfifo average packet size in bytes. Used in calculations for queue limits. Adjust if you know your game traffic has a significantly different average packet size. | integer | 450 |
netemdelayms | Artificial delay added by netem in milliseconds, only used if 'gameqdisc' is set to 'netem'. This is useful for testing or simulating higher latency connections. Netem applies the delay in both directions, so if you set a delay of 10 ms, you will experience a total of 20 ms cumulative delay. | integer | 30 |
netemjitterms | Jitter added by netem in milliseconds. Simulates network variability, useful for testing how applications handle inconsistent latency. | integer | 7 |
netemdist | Distribution of delay for netem. Options affect how the artificial delay is applied, simulating different network conditions. | enum (uniform, normal, pareto, paretonormal) | normal |
pktlossp | Packet loss percentage for netem. Simulates network packet loss, useful for testing application resilience. | string | none |
All cake settings are described in the tc-cake man.
Config option | Description | Type | Default |
---|---|---|---|
COMMON_LINK_PRESETS | Preset for common link types. Affects overhead calculations and default behaviors. 'ethernet' or 'conservative' is suitable for most connections. | enum (ethernet, docsis, ... see cake man.) | ethernet |
OVERHEAD | Manual overhead setting. If set, overrides the preset. Useful for fine-tuning or unusual setups. | integer | |
MPU | Minimum packet unit size. If set, overrides the preset. | integer | |
LINK_COMPENSATION | Additional compensation for link peculiarities. | string (atm, ptm, noatm) | |
ETHER_VLAN_KEYWORD | Keyword for Ethernet VLAN compensation. Used when VLAN tagging affects packet sizes. | string | |
PRIORITY_QUEUE_INGRESS | Priority queue handling for incoming traffic. 'diffserv4' uses 4 tiers of priority based on DSCP markings. | enum (diffserv3, diffserv4, diffserv8) | diffserv4 |
PRIORITY_QUEUE_EGRESS | Priority queue handling for outgoing traffic. Usually matched with INGRESS for consistency. | enum (diffserv3, diffserv4, diffserv8) | diffserv4 |
HOST_ISOLATION | Enables host isolation in CAKE. Prevents one client from monopolizing bandwidth, ensuring fair distribution among network devices. (dual-srchost/dual-dsthost) | boolean | 1 |
NAT_INGRESS | Enables NAT lookup for incoming traffic. Important for correct flow identification in NAT scenarios. | boolean | 1 |
NAT_EGRESS | Enables NAT lookup for outgoing traffic. | boolean | 1 |
ACK_FILTER_EGRESS | Controls ACK filtering. 'auto' enables it when download/upload ratio ≥ 15, helping to prevent ACK floods on asymmetric connections. | enum (auto, 1, 0) | auto |
RTT | Round Trip Time estimation. If set, used to optimize CAKE's behavior for your specific network latency. | integer | |
AUTORATE_INGRESS | Enables CAKE's automatic rate limiting for ingress. Can adapt to changing network conditions but may be less predictable. | boolean | 0 |
EXTRA_PARAMETERS_INGRESS | Additional parameters for ingress CAKE qdisc. For advanced tuning, allows passing custom options directly to CAKE. | string | |
EXTRA_PARAMETERS_EGRESS | Additional parameters for egress CAKE qdisc. Similar to INGRESS, but for outgoing traffic. | string |
Config option | Description | Type | Default |
---|---|---|---|
PRESERVE_CONFIG_FILES | If enabled, configuration files are preserved during system upgrades. Ensures your QoS settings survive firmware updates. | boolean | 1 |
WASHDSCPUP | Sets DSCP to CS0 for outgoing packets after classification | boolean | 1 |
WASHDSCPDOWN | Sets DSCP to CS0 for incoming packets before classification | boolean | 1 |
BWMAXRATIO | Maximum ratio between download and upload bandwidth. Prevents ACK floods on highly asymmetric connections by limiting download speed relative to upload. | integer | 20 |
ACKRATE | Sets rate limit for TCP ACKs, helps prevent ACK flooding / set to 0 to disable ACK rate limit | integer | (UPRATE * 5 / 100) |
UDP_RATE_LIMIT_ENABLED | Downgrades UDP traffic exceeding 450 pps to lower priority | boolean | 1 |
UDPBULKPORT | UDP ports for bulk traffic. Often used for torrent traffic. Helps identify and manage high-bandwidth, lower-priority traffic. | string | |
TCPBULKPORT | TCP ports for bulk traffic. Comma-separated list or ranges. Similar to UDPBULKPORT, but for TCP-based bulk transfers. | string | |
VIDCONFPORTS | [Legacy - use rules] Ports used for video conferencing and other high priority traffic. Uses the Fast Non-Realtime (1:12) queue. | string | |
REALTIME4 | [Legacy - use rules] IPv4 addresses of devices to receive real-time priority (Only UDP). Useful for gaming consoles or VoIP devices that need consistent low latency. | string | |
REALTIME6 | [Legacy - use rules] IPv6 addresses for real-time priority. Equivalent to REALTIME4 but for IPv6 networks. | string | |
LOWPRIOLAN4 | [Legacy - use rules] IPv4 addresses of devices to receive low priority. Useful for limiting impact of bandwidth-heavy but non-time-sensitive devices. | string | |
LOWPRIOLAN6 | [Legacy - use rules] IPv6 addresses for low priority. Equivalent to LOWPRIOLAN4 but for IPv6 networks. | string |
QoSmate allows you to define custom DSCP (Differentiated Services Code Point) marking rules to prioritize specific types of traffic. These rules are defined in the /etc/config/qosmate
file under the rule
sections and via luci-app-qosmate.
Config option | Description | Type | Default |
---|---|---|---|
name | A unique name for the rule. Used for identification and logging. | string | |
proto | The protocol to match. Determines which type of traffic the rule applies to. | enum (tcp, udp, icmp) | |
src_ip | Source IP address or range to match. Can use CIDR notation for networks. | string | |
src_port | Source port or range to match. Can use individual ports or ranges like '1000-2000'. | string | |
dest_ip | Destination IP address or range to match. Similar to src_ip in format. | string | |
dest_port | Destination port or range to match. Similar to src_port in format. | string | |
class | DSCP class to assign to matching packets. Determines how the traffic is prioritized in the QoS system. | enum (cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef) | |
counter | Enable packet counting for this rule. Useful for monitoring and debugging. | boolean | 0 |
config rule
option name 'gaming_traffic'
option proto 'udp'
option src_ip '192.168.1.100'
option dest_port '3074'
option class 'cs5'
option counter '1'
This rule would mark UDP traffic from IP 192.168.1.100 to port 3074 with the CS5 DSCP class, which is typically used for gaming traffic, and enable packet counting for this rule.
Prioritizing Video Conferencing Traffic:
config rule
option name 'zoom_traffic'
option proto 'tcp udp'
list dest_port '3478-3479'
list dest_port '8801-8802'
option class 'af41'
option counter '1'
Explanation: This rule marks both TCP and UDP traffic to typical Zoom ports with the DSCP class AF41. Using list
for dest_port
allows specifying multiple port ranges. AF41 is well-suited for interactive video conferencing as it provides high priority without impacting the highest priority traffic.
Low Priority for Peer-to-Peer Traffic:
config rule
option name 'p2p_traffic'
option proto 'tcp udp'
list src_port '6881-6889'
list dest_port '6881-6889'
option class 'cs1'
option counter '1'
Explanation: This rule assigns low priority to P2P traffic (like BitTorrent) by marking it as CS1. Using list
for both src_port
and dest_port
covers both incoming and outgoing P2P traffic.
Call of Duty Game Traffic:
config rule
option name 'cod1'
option proto 'udp'
option src_ip '192.168.1.208'
option src_port '3074'
option dest_port '30000-65535'
option class 'cs5'
option counter '1'
config rule option name 'cod2' option proto 'udp' option dest_ip '192.168.1.208' option dest_port '3074' option class 'cs5' option counter '1'
Explanation: These rules prioritize Call of Duty game traffic. The first rule targets outgoing traffic from the game console (IP 192.168.1.208), while the second rule handles incoming traffic. Both use CS5 class, which is typically used for gaming traffic due to its high priority. The wide range of destination ports in the first rule covers the game's server ports.
4. Generic Game Console/Gaming PC Traffic:
config rule option name 'Game_Console_Outbound' option proto 'udp' option src_ip '192.168.1.208' list dest_port '!=80' list dest_port '!=443' option class 'cs5' option counter '1'
config rule option name 'Game_Console_Inbound' option proto 'udp' option dest_ip '192.168.1.208' list src_port '!=80' list src_port '!=443' option class 'cs5' option counter '1'
Explanation: These rules provide a more generic approach to prioritizing game console/gaming pc traffic. The outbound rule prioritizes all UDP traffic from the console (192.168.1.208) except for ports 80 and 443 (common web traffic). The inbound rule does the same for incoming traffic. This approach ensures that game-related traffic gets priority while allowing normal web browsing to use default priorities. The use of '!=' (not equal) in the port lists demonstrates how to exclude specific ports from the rule.
This is more or less equivalent to the `realtime4` and `realtime6` variables from the SimpleHFSCgamer script. However, this rule is even better as it excludes UDP port 80 and 443, which are often used for QUIC. This is likely less of an issue on a gaming console than on a gaming PC, where a YouTube video using QUIC might be running alongside the game.
This rule is also applied when the auto-setup is used via CLI or UI and a Gaming Device IP (optional) is entered.
## Command Line Interface
QoSmate can be controlled and configured via the command line. The basic syntax is:
/etc/init.d/qosmate [command]
Available commands: start Start the service stop Stop the service restart Restart the service reload Reload configuration files (or restart if service does not implement reload) enable Enable service autostart disable Disable service autostart enabled Check if service is started on boot running Check if service is running status Service status trace Start with syscall trace info Dump procd service info check_version Check for updates update Update qosmate auto_setup Automatically configure qosmate expand_config Expand the configuration with all possible options auto_setup_noninteractive Automatically configure qosmate with no interaction
### Update QoSmate
/etc/init.d/qosmate update
## Troubleshooting
If you encounter issues with the script or want to verify that it's working correctly, follow these steps:
1. Disable DSCP washing (egress and ingress)
2. Update and install tcpdump: `opkg update && opkg install tcpdump`
3. Mark an ICMP ping to a reliable destination (e.g., 1.1.1.1) with a specific DSCP value using a DSCP Marking Rules.
4. Ping the destination from your LAN client.
5. Use `tcpdump -i <your wan interface> -v -n -Q out icmp` to display outgoing traffic (upload) and verify that the TOS value is not 0x0. Make sure to **set the right interface (WAN Interface).**
6. Use `tcpdump -i ifb-<your wan interface> -v -n icmp` to display incoming traffic (download) and verify that the TOS value is not 0x0. Make sure to **set the right interface (ifb + <yourwaninterface)**
7. Install watch: `opkg update && opkg install procps-ng-watch`
8. Check traffic control queues:
- When using HFSC as root qdisc:
watch -n 2 'tc -s qdisc | grep -A 2 "parent 1:11"'
```
Replace "1:11" with the desired class. The packet count should increase with the ping in both directions.
When using CAKE as root qdisc:
watch -n 1 'tc -s qdisc show | grep -A 20 -B 2 "diffserv4"'
The output will show you if packets are landing in the correct queue.
WIP... (Include additional troubleshooting steps, such as how to verify if QoSmate is working correctly, common issues and their solutions, etc.)
To remove QoSmate from your OpenWrt router:
/etc/init.d/qosmate stop
rm /etc/init.d/qosmate /etc/qosmate.sh /etc/config/qosmate
rm -r /www/luci-static/resources/view/qosmate
rm /usr/share/luci/menu.d/luci-app-qosmate.json
rm /usr/share/rpcd/acl.d/luci-app-qosmate.json
/etc/init.d/rpcd restart
/etc/init.d/uhttpd restart
cd /path/to/your/openwrt
mkdir -p package/qosmate git clone https://github.com/hudra0/qosmate.git package/qosmate
mkdir -p package/luci-app-qosmate git clone https://github.com/hudra0/luci-app-qosmate.git package/luci-app-qosmate
Contributions to QoSmate are welcome! Please submit issues and pull requests on the GitHub repository.
QoSmate is inspired by and builds upon the work of SimpleHFSCgamerscript, SQM, cake-qos-simple, qosify and DSCPCLASSIFY. I thank all contributors and the OpenWrt community for their valuable insights and contributions.