DSCP Classify - Service for applying DSCP class to connections [22.03-24.10.x]

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

  1. 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'.

  1. 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

image
image

Associated discussions

Acknowledgements

I'd like to thank @ldir and @amteza for their great suggestions and contributions!

16 Likes

Great work!

Question: you have a WMM node in which you seem to over-write DSCPs so that intent maps to the the right (we can argue about that :wink: *) AC for each DSCP. I would argue that instead of re-writing DSCPs over and over again, we might be better of using qos_map_set to configure the desired DSCP to AC mapping for the AP and all stations instead?

*) Neither AC_VI and especially not AC_VO are without considerable side-effects on "normal" traffic in AC_BE (both by taking weighted priority in air access as well as reducing the total WiFi segment capacity by limiting aggregation duration for AC_VO), so it is arguable whether one should actually move all that much traffic to the higher classes. I know that https://www.rfc-editor.org/rfc/rfc8325 seems to endorse such usage of ACs, but I note that rfc8325 is pretty thin on studies actually showing the consequences of doing so... so IMHO rfc8325 is decent information how to map different PHBs to WiFi but one first should figure out whether one wants to give a specific PHB special treatment over WiFi in the first place.

1 Like

Fair points, I know we've discussed before too :slight_smile: I make use of it in my setup as my mesh APs are running stock firmware.
What I can do is make this off by default and then it's down to the user to decide whether they want to use it with their setup (which feels like a good compromise given the RFC's draft status).

3 Likes

Good argument! I had only considered the full OpenWrt APs case here and forgot about non-qos-map configurable APs at all.

That would be a safer default IMHO that still allows users to opt in (I am a big fan of opt-in, but also of sane defaults and here the best path is unclear to me).

great script thanks again,

I don't know yet if there is counter addition in your repository ?

to be sure and help people in sqm we have to put like your image

DO not Squash

allow

ECN (by default )

ECN

I also noticed a problem with your repository

if I take from github on your repository my rules

in the chain static class don't work all

if I take from Ldir in these cases it works all I put you in illustration the error :wink:

type or paste code here

Yes I've added the counter option now :slightly_smiling_face:

You can enable counters for a particular rule by adding the option

option counter '1'

That's correct yes: do not squash, allow.

You can leave the ECN settings at their default values.

2 Likes
  chain static_classify {
                meta l4proto { tcp, udp } th dport { 53, 853, 5353 } goto ct_set_cs2 comment "DNS"
                ip saddr 192.168.2.160 tcp dport 1935 counter packets 0 bytes 0 goto ct_set_cs3 comment "twitch1"
                ip dscp != { cs0, cs6, cs7 } iifname != { "wan" } (@nh,8,8 & 0xfc) >> 2 vmap @dscp_ct
                ip6 dscp != { cs0, cs6, cs7 } iifname != { "wan" } (@nh,0,16 & 0xfc0) >> 6 vmap @dscp_ct
                meta l4proto != { tcp, udp } goto ct_set_cs0
                ct mark set ct mark & 0xffffff80 | 0x00000080

my rules for consoles game ps5 doesn't appair so if i take to Ldir he appair i don't know if you undesrtand ?

config rule
        option name 'PS5udp'
        list proto 'udp'
        list src_ip '192.168.2.160'
	list dest_port '!80'
	list dest_port '!443'
	option class 'cs4'
        option family 'ipv4'
	option counter '1'

i has just dns and twitch1

1 Like

Ahh yes I see you're making use of the negative matching present in the latest commit from @amteza in @ldir's fork.
I'm looking to merge that functionality into the main branch in a couple of hours, will update back here once it's ready. :slightly_smiling_face:

4 Likes

ok great so I could take from your repository

on the hand or developped ??

the most recent I could see in terms of time

and thanks for the ECN

so
ECN (by default) the first one
and NOECN (by default) the second one :slight_smile:

and not "ECN" the second

cake will ignore the ECN setting in the GUI and always use ECN if the packets have either ECT(0) or ECT(1) set. (Or cake is already in emergency drop mode or the respective flow triggered cake's BLUE mode which IIRC drops hard).

2 Likes

It's not committed to develop yet.

2 Likes

That’s what I also suggested in my thread as new users could get confused if their static marks are overwritten when wmm is enabled.

One thing that always comes to my mind when i think about dscpclassify is: do you inted to make a luci app for dscpclassify? Or could it maybe be integrated into the luci firewall?

Setting dscp through luci firewall would probably already work with your script. I have to try that…

2 Likes

DSCPCLASSIFY PARAMETER

yes it would be a great idea if by luci we could put it as hudra suggests but I think the work would be long?
if we could integrate our dscpclassify parameters like in my thread

it would be christmas for the first time in such a short time :sweat_smile:

yes exactly :wink:

I will wait for your last merge to update the script,

@Hudra yes I also have the same little problem as you the counter seems to be blocked especially for twitch1

 ip saddr 192.168.2.160 tcp dport 1935 counter packets 1 bytes 60 goto ct_set_cs3 comment "twitch1"

Actually, I don’t have any problem, maybe you misunderstood something:

In this post I just wanted to make clear that I think it would be better to disable the option wmm by default. But I was too slow as @yelreve already fixed it in his repository.

If you are referring to my thread where I asked why my counters are not increasing by much when the option “counter” is set here is your answer:

So, if you have 1 packet in your counter it probably works and you won’t ever see counters increasing for every packet. Only for every flow… at least unless there is an option to use counters from conntrack but I don’t know if this is possible.

3 Likes

I've updated the main branch now with the negative matching ability, I took it one step further to allow mixing both negative and positive matches on a single rule (though probably a fairly niche use case).

@anon78773196 I think your config in thread Sharing dscpclassify configuration on OpenWrt should now work as expected with the main code branch. :slight_smile:

It also includes the auto-merge tweak for sets with intervals.

@Hudra you're correct, the rule counters only count matched connections (not every packet in the connection).

7 Likes

may i ask what negative matching mean ??

It allows you to write a rule which would match everything except the entries you've specified with an '!'.
For example the below would match all tcp/udp connections that did not have a destination port of 443 or 80.

config rule
	option name 'Not HTTP'
	list proto		'tcp'
	list proto		'udp'
	list dest_port	'!443'
	list dest_port	'!80'
	option class 'cs4'
3 Likes

is it the same as writing nowash in iqdisc_opts and eqdisc_opts right ??
what if i only wash on egress ?

In SQM setup those two parameters correspond to the following options

Squash DSCP on inbound packets (ingress) = squash_dscp
Ignore DSCP on ingress = squash_ingress

You're correct, setting squash_dscp to 0 (allow) is equivalent to nowash in iqdisc_opts.

Enabling squash/wash has the effect of making cake overwrite the DSCP to 0 after passing through the tc qdisc, however DSCP classify would re-apply it from the conntrack for lan bound packets.

squash_ingress doesn't seem to actually do anything in my testing this morning. *Edit: per @moeller0's note below this is because I'm specifying a diffserv in my qdisc_opts.

Washing on WAN egress via eqdisc_opts would make sure your DSCPs are all set to CS0 when sent to your ISP after passing through the qdisc - that could be beneficial depending on how your ISP handles different DSCP marks.

4 Likes