This thread is a centralised place for discussing my nftables 'dscpclassify' service for applying DSCP class to connections.
I will update this post with up to date information as the service is enhanced and welcome ideas and people's inputs.
What is DSCP Classify?
DSCP Classify is an nftables based service for applying DSCP classifications to connections, compatible with OpenWrt's firewall4 for dynamically setting DSCP packet marks (this only works in OpenWrt 22.03 and above).
This should be used in conjunction with layer-cake SQM queue with ctinfo configured to restore DSCP on the device ingress.
The dscpclassify service uses the last 8 bits of the conntrack mark (0x000000ff).
Latest release
OpenWrt 22.03-24.10.x
Release notes
Please raise issues/suggestions for improvement
https://github.com/jeverley/dscpclassify/issues
If available please include the debug file /tmp/dscpclassify.debug
as this will help with troubleshooting.
Classification modes
The service uses three methods for classifying and DSCP marking connections outlined below.
1. User rules
The service will first attempt to classify new connections using rules specified by the user in the config file.
These follow a similar syntax to the OpenWrt firewall config and can match upon source/destination ports and IPs, firewall zones etc.
The rules support the use of nft sets, which could be dynamically updated from external sources such as dnsmasq.
2. Client DSCP hinting
The service can be configured to apply the DSCP mark supplied by a non WAN originating client.
This function ignores CS6 and CS7 classes to avoid abuse from inappropriately configed LAN clients such as IoT devices.
3. Dynamic classification
Connections that do not match a user rule or client hint will be dynamically classified by the service to reduce their priority.
Multi-connection client port detection for detecting P2P traffic
These connections are classified as Low Effort (LE) by default and therefore prioritised below Best Effort traffic when using the layer-cake qdisc.
Multi-threaded service detection for identifying high-throughput downloads from services such as Steam
These connections are classified as High-Throughput (AF13) by default and therefore prioritised as follows by cake:
- diffserv3/4: prioritised equal to Best Effort (CS0) traffic
- diffserv8: prioritised below Best Effort (CS0) traffic, but above Low Effort (LE) traffic
Service installation
- To install the main dscpclassify service via command line you can use the following commands
repo="https://raw.githubusercontent.com/jeverley/dscpclassify/main"
mkdir -p "/etc/dscpclassify.d"
if [ ! -f "/etc/config/dscpclassify" ]; then
wget "$repo/etc/config/dscpclassify" -O "/etc/config/dscpclassify"
else
wget "$repo/etc/config/dscpclassify" -O "/etc/config/dscpclassify_git"
fi
wget "$repo/etc/dscpclassify.d/main.nft" -O "/etc/dscpclassify.d/main.nft"
wget "$repo/etc/dscpclassify.d/maps.nft" -O "/etc/dscpclassify.d/maps.nft"
wget "$repo/etc/dscpclassify.d/verdicts.nft" -O "/etc/dscpclassify.d/verdicts.nft"
wget "$repo/etc/hotplug.d/iface/21-dscpclassify" -O "/etc/hotplug.d/iface/21-dscpclassify"
wget "$repo/etc/init.d/dscpclassify" -O "/etc/init.d/dscpclassify"
chmod +x "/etc/init.d/dscpclassify"
/etc/init.d/dscpclassify enable
/etc/init.d/dscpclassify start
Ingress DSCP marking requires the SQM queue setup script 'layer_cake_ct.qos' and the package 'kmod-sched-ctinfo'.
- To install the SQM setup script via command line you can use the following commands:
repo="https://raw.githubusercontent.com/jeverley/dscpclassify/main"
opkg update
opkg install kmod-sched-ctinfo
wget "$repo/usr/lib/sqm/layer_cake_ct.qos" -O "/usr/lib/sqm/layer_cake_ct.qos"
wget "$repo/usr/lib/sqm/layer_cake_ct.qos.help" -O "/usr/lib/sqm/layer_cake_ct.qos.help"
Service configuration
The user rules in '/etc/config/dscpclassify' use the same syntax as OpenWrt's firewall config, the 'class' option is used to specified the desired DSCP.
A working default configuration is provided with the service which should work for most users.
The service supports the following configuration options
Config option | Description | Type | Default |
---|---|---|---|
class_bulk | The class applied to threaded bulk clients | string | le |
class_high_throughput | The class applied to threaded high-throughput services | string | af13 |
client_hints | Adopt the DSCP class supplied by a non-WAN client (this exludes CS6 and CS7 classes to avoid abuse) | boolean | 1 |
threaded_client_min_bytes | The total bytes before a threaded client port (i.e. P2P) is classified as bulk | uint | 10000 |
threaded_client_min_connections | The number of established connections for a client port to be considered threaded | uint | 10 |
threaded_service_min_bytes | The total bytes before a threaded service's connection is classed as high-throughput | uint | 1000000 |
threaded_service_min_connections | The number of established connections for a service to be considered threaded | uint | 3 |
lan_device | Manually specify devices that the service should treat as LAN | list: string | |
lan_zone | Manually specify firewall zones that the service should treat as LAN | list: string | lan |
wan_device | Manually specify devices that the service should treat as WAN | list: string | |
wan_zone | Manually specify firewall zones that the service should treat as WAN | list: string | wan |
wmm | When enabled the service will mark LAN bound packets with DSCP values respective of WMM (RFC-8325) | boolean | 0 |
Example user rule
config rule
option name 'DNS'
list proto 'tcp'
list proto 'udp'
list dest_port '53'
list dest_port '853'
list dest_port '5353'
option class 'cs5'
option counter '0'
The counter option can be enabled to count the number of matched connections for a rule.
The OpenWrt firewall syntax is outlined here.
SQM configuration
The 'layer_cake_ct.qos' queue setup script must be selected for your wan device in SQM setup,
It is important that Ignore DSCP on ingress is Allow in SQM setup otherwise cake will ignore the service's DSCP classes.
Below is validated working SQM config for use with the service
Config parameter | Value |
---|---|
qdisc_advanced | 1 |
squash_dscp | 0, to ensure cake does not remove ingress packet DSCP values |
squash_ingress | 0, to ensure cake looks at packet marks on ingress |
qdisc_really_really_advanced | 1 |
iqdisc_opts | nat dual-dsthost ingress diffserv4 |
eqdisc_opts | nat dual-srchost ack-filter diffserv4 |
script | layer_cake_ct.qos |
Associated discussions
Acknowledgements
I'd like to thank @ldir and @amteza for their great suggestions and contributions!