Ethernet DSCP to WiFi QoS Mapping

Hello !
I've scoured the documentation and forum but couldn't find the answer (at least didn't see it explicitly with my noob eyes)

I have a TP-link Archer C7 V5, with firmware OpenWrt 19.07.

I'm sending packets marked DSCP 46 on the wire side, which normally results in QoS 6 priority (voice). However, I get only priority 5 (video) when I test with a wireshark capture.

How can I fix the DSCP to QoS mapping ?

Thank you very much,
Arno

this is standard behavior in Linux wifi drivers, and I agree very irritating... there is some code in hostapd to set up this mapping but last I checked about a year ago, it wasn't in openwrt.

there are a couple threads that discuss this

https://forum.openwrt.org/search?q=hostapd%20dscp

I see, messing with hostapd. I will give it a shot and give feedback!
Is the iptables command/firewall ersatz/crowbar of any use ?

Ah I noticed the part of the discussion that said the hostapd modification is a challenge in OpenWrt. Alright, will try to see if I can figure it out, running grep -r qos_map /; to see if I find where it is defined and/or from what script it is generated.

That'd be great! In the mean time I've redefined all my devices to use dscp CS6 = 48 instead of EF=46 and that works out of the box.

I believe this is the standard IEEE mapping, nothing Linux specific here... Also @ArnoLP if you use AC_VO on wifi make sure that you understand the tradeoff, AC_VO does only allows less aggregation that e.g. AC_VI and hence, since the per TX-OP overhead stays pretty much the same is less bandwidth efficient than the lower ACs. If the traffic you want to route to AC_VO is sparse, then you are all set, but if you flood AC_VO you will effectively dronw out all other users of the same channel, including traffiv in AC_VI , AC_BE, AC_BK, but also traffic on neighboring APs on the same channel.... So by all means, use AAC_VO, but please consider the side-effects before doing so blindly. :wink:

Have a look at the hostapd_cli help output, at least in master you will find among others:

set_qos_map_set <arg,arg,...> = set QoS Map set element
send_qos_map_conf <addr> = send QoS Map Configure frame

These look like methods useful for testing at least.... (Playing with these is on my TODO stack, but time is constantly short and other things interfere).

It's been bog standard since the early days of DSCP for SIP based VOIP phones to use EF=46 for their audio. I can't understand why anyone would think that shouldn't go into the AC_VO queue. It is explicitly for VOICE.

What linux does is essentially pretend that DSCP is IP precedence, which is the same thing as mapping all DSCP to their CS class... it puts:

  1. CS1 and CS2 in Bulk
  2. CS0, CS3 in Best Effort
  3. CS4, CS5 (which includes EF) in Video
  4. CS6, CS7 in Voice

Documentation here: https://wireless.wiki.kernel.org/en/developers/documentation/mac80211/queues

Whether this is IEEE standard or not, the de facto standard for voice is EF which maps to CS5, but should go in the VOICE queue, because the voice queue behavior was explicitly designed for voice traffic.

Some common commercial switches use slightly different mappings, taking straight IP precedence, such as the gazillion units sold sg108e: https://static.tp-link.com/2019/201912/20191220/1910012686_Easy%20Smart%20Switch_UG.pdf

it does:

  1. CS0, CS1 = low
  2. CS2, CS3 = normal
  3. CS4,CS5 = medium
  4. CS6, CS7 = high

To accomodate all this utter baloney, I retag all my CS0 traffic as CS3.

I use CS1 for bulk traffic (like long-running downloads), CS2 for NFS filesystem traffic, CS4 for streaming video, CS5 for game traffic and CS6 for voice

hardcore gamers should probably use CS6 for UDP game traffic as well.

Cake on the other hand does something different: https://github.com/torvalds/linux/blob/master/net/sched/sch_cake.c

  1. CS1 = bulk
  2. CS0, everything else = best effort
  3. AF4x, AF3x, CS3, AF2x, CS2 = video
  4. CS4, CS5, CS6, CS7, EF, VA = voice

As you can see, if you have a packet go WAN -> Cake -> Smart Switch -> AP there is a pretty strong impedance mismatch at every step...

For example, if you leave CS0 on a default packet, it will go into best effort in cake, low priority in the switch, and best effort in the AP.

On the other hand if you put CS1 for bulk, it will go Bulk in cake, best-effort in the switch (ahead of CS0), and Bulk in the AP.

Suppose you change your CS0 default to CS2: it'll go VIDEO in cake, Normal in the switch, and BULK in the AP...

Suppose you change your CS0 default to CS3: It'll go VIDEO in cake, normal in the switch, and Best Effort in the AP...

Rolling my eyes so hard it hurts! :roll_eyes:

Fortunately the switch is probably less important, unless you have lots of bulk transfers like heavy NFS traffic or a big network of video surveillance cameras, you can probably get away with not worrying about the difference between say bulk and best effort and just being satisfied that things like game and voice packets wind up in high prio in the switch...

The choke points for most people are at the WAN and the AP. But gigabit WAN is becoming a more common thing! At that point choke points are mainly in the AP!

2 Likes

Well, the only indication is in the _VO part of AC_VO, would you still use the same arguments of the name would be AC_NC for network control? ;).
Given that WMM implements a rather strict priority system (AC_VO can shut out AC_BE and AC_BK completely, thereby starving all flows in those ACs) I do believe that we are lucky that EF maps into AC_VI, there is quite a number of applications that use EF without being considerate about bandwidth...
That said the IETF is on your side (see [https://tools.ietf.org/html/rfc8325])(https://tools.ietf.org/html/rfc8325), but again I note that that RFC does not cite actual studies supporting the proposed mappings. Now, I agree that conceptionally these proposed mappings seem sane, but I am always a bit weary about unexpected side-effects especially when the side-effects can be to effectively starve all other lower priority users of the same WiFi channel...

I actually believe this to be sane, the highest priority tier (in a strict priority scheme) should be reserved for carefully selected admission controlled traffic :wink:

Honestly, I think that the whole 6 dscp bits should be partitioned into two groups of three, 3 bits for the current networks re-mapped DSCP and 3 bits for the DSCP the sending endpoint requested. That way the intent remains conserved and the intermediate hops have a chance of doing their own thing. But I digress.

IMHO this is rather sane and similar to how the priority levels should have been implemented in the first place. Alas, I also understand why BK was hoisted to CS1 initially, to stay backward compatible and do no harm to innocent bystanders...

I knew you did that and always wondered why exactly, now I know, and as I assumed with a decent rationale. :wink:

Well, I try to keep things simple, but I also like to use 3 tiers: BK, BE, and IMPORTANT, but I basically want these as infrastructure which I rarely exercise (I think I elevate ssh into IMPORTANT). But again I run a fairly small, well-behaved network wich avoids all the tricky infrastructure pieces that require special care :wink: (opting for a ip-phone base connected via ethernet to my router and use DECT for allowing to use the handset in the whole apartment avoids a lot of complications).

Yes, that is an unfortunate default in the switch (understandable and clean, but unfortunate), I do have no issues with cake putting EF, VA in the highest tier as cake will take care not to starve the lower tiers (unlike WMM).

I feel your pain.

Yes we are getting there! I believe that at least for Wifi <6 the airtime fairness approach pioneered by @tohojo and others in ath9k and ath10k goes a long way in making wifi have acceptable latency under load.

Wow didn't see the follow up answers. Thanks for all the discussions, @dlakelan I'll be reading the references and trying to catch up.
@moeller0 I'll be sure to check hostapd_cli .

Thank you very much for the help. I'll update on monday, I'll just disconnect my brain from these issues for the weekend.

Hello,
I tried the suggestion of @moeller0 and checked out hostapd_cli, I figured out it's a package you have to install, that took me a while to understand. Ran it and attempted hostapd_cli set_qos_map_set 46,6 and got an error UNKNOWN COMMAND. I typed in hostapd_cli wlfjhfljhlfwgerh to see what kind of error I get and it was Unknown command : 'wlfjhfljhlfwgerh', so I'm guessing UNKNOWN COMMAND in all capital letters must come from some underlying utility (I am told hostapd itself which hostapd_cli is the interface of)

Anyway, that finishes convincing me fixing that video priority issue is difficult and the tools aren't easy to use (or working) to do the fixes, so I consider I've gone far enough and am giving up and not looking into this issue anymore.

Thanks a lot for the information and input however, I'm very happy to have learnt a few things and will remember to come back here if for some reason I REALLY have to try to find a solution.

All the best,
Arno.

1 Like

Once hostapd in OpenWrt supports this feature out of the box, it should be relatively easy. In the mean time, you can use iptables to retag traffic with DSCP EF to DSCP CS6 which will put it into WMM voice queue.

it's not that hard. Is this Archer C7 running as an AP or as your main router?

1 Like

Mmmh, so it could be that OpenWrt has that hostapd feature disabled, and/or that '46,6' is a malformed qos_map according to https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf:

# QoS Map Set configuration
#
# Comma delimited QoS Map Set in decimal values
# (see IEEE Std 802.11-2012, 8.4.2.97)
#
# format:
# [<DSCP Exceptions[DSCP,UP]>,]<UP 0 range[low,high]>,...<UP 7 range[low,high]>
#
# There can be up to 21 optional DSCP Exceptions which are pairs of DSCP Value
# (0..63 or 255) and User Priority (0..7). This is followed by eight DSCP Range
# descriptions with DSCP Low Value and DSCP High Value pairs (0..63 or 255) for
# each UP starting from 0. If both low and high value are set to 255, the
# corresponding UP is not used.
#
# default: not set
#qos_map_set=53,2,22,6,8,15,0,7,255,255,16,31,32,39,255,255,40,47,255,255

so that would probably mean something like:
46,6, 0,0,8,7,255,255,9,63,255,255,255,255,255,255,255,255,255,255
to move DSCP 46 aka EF into UP6 aka AC_VO, DSCP 8 aka CS1 into UP1 aka AC_BK, and all the rest into UP0 aka AC_BE, not sure whether that works that will work any better...

Unless people request this feature and test what works and what does not work OpenWrt support for this is going to be unlikely though. So thanks @ArnoLP for testing!

I think this has a bug.

first off, there are user priorities 0 through 7. DSCP gets mapped to those, and then those get mapped to the 4 queues (BK, BE, VI, VO)

According to https://wireless.wiki.kernel.org/en/developers/documentation/mac80211/queues

The UP values 1,2 are mapped to Bulk, 0,3 to BE, 4,5 to VI, and 6,7 to VO.

so let's set up qos_map_set as follows, which uses only ranges, and simply moves the lower end of the UP7 down to 46 = EF

0,7,8,15,255,255,24,31,32,39,40,45,46,55,56,63

This will put CS0 into UP0 = BE, CS1 into BK, CS4,CS5 and related things into VI and EF and above into VO.

1 Like

I tried using the above, and I also get UNKNOWN COMMAND. I think maybe the hostapd doesn't support qos_map_set

I'm running wpad on this device, it's still got 18.06.2 and running as an AP.

1 Like

I guess, I need to test it with master and 19.07.0 (which upgrades to hostapd 2.9), but I fear that it might simply be not configured in OpenWrt to save space. Time to see whether I can easily change that for a private build...

and file a bug :wink: I can't imagine the space savings is much, and QoS is a major feature that is constantly requested on the forum, so I don't think it's a good candidate to leave out.

Sure it should have been
46,6,0,7,8,8,9,63,255,255, 255,255, 255,255, 46,46, 255,255

The goal really is to only move 46 to EF for testing, and keep everything else <= AC_BE, so the gap in AC_VI was intentional. This was not intended as a proposal for a final mapping but just enough to be able to use

cat /sys/kernel/debug/ieee80211/phy0/ath9k/xmit
cat /sys/kernel/debug/ieee80211/phy1/ath9k/xmit

e.g.:

root@router:~# cat /sys/kernel/debug/ieee80211/phy0/ath9k/xmit
                            BE         BK        VI        VO

MPDUs Queued:              195          2         4       780
MPDUs Completed:           286          6         9      1844
MPDUs XRetried:             30          0         0         1
Aggregates:             302919        428       185         0
AMPDUs Queued HW:            0          0         0         0
AMPDUs Completed:      2468561      11721      5621         0
AMPDUs Retried:          27392         56        44         0
AMPDUs XRetried:           417          2         6         0
TXERR Filtered:              0          0         0         0
FIFO Underrun:               0          0         0         0
TXOP Exceeded:               0          0         0         0
TXTIMER Expiry:              0          0         0         0
DESC CFG Error:              0          0         0         0
DATA Underrun:               0          0         0         0
DELIM Underrun:              0          0         0         0
TX-Pkts-All:           2469294      11729      5636      1845
TX-Bytes-All:       3250762776    5762717   3535214    517318
HW-put-tx-buf:               1          1         1         1
HW-tx-start:           1872330      11011      5015      1845
HW-tx-proc-desc:       1872330      11011      5015      1845
TX-Failed:                   0          0         0         0

to see _VI counters selectively increase when a test ping flood with EF set is directed to one of the internal hosts.

EDIT:
As both of you already expected, even on master it does not work:

root@router:~# hostapd_cli set_qos_map_set 46,6,0,7,8,8,9,63,255,255,255,255,255,255,46,46,255,255
Selected interface 'wlan0'
UNKNOWN COMMAND
root@router:~# 

It looked so easy, just uncomment CONFIG_INTERWORKING=y in
package/network/services/hostapd/files/hostapd-full.config
and
package/network/services/hostapd/files/wpa-supplicant-full.config

# Interworking (IEEE 802.11u)                                                                                                       
# This can be used to enable functionality to improve interworking with                                                             
# external networks (GAS/ANQP to learn more about the networks and network                                                          
# selection based on available credentials).                                                                                        
#CONFIG_INTERWORKING=y  

But alas this runs into a compile error and I run out of time....

I've gotten it to compile by setting CONFIG_INTERWORKING=y and CONFIG_HS20=y in hostapd-full.config and wpa-supplicant-full.config. In my build I selected wpad-openssl and hostapd-utils. So far I have done the following:

root@telia:~# hostapd_cli -i wlan0 set_qos_map_set 0,63,255,255,255,255,255,255,
255,255,255,255,255,255,255,255
OK
root@telia:~# hostapd_cli -i wlan1 set_qos_map_set 0,63,255,255,255,255,255,255,
255,255,255,255,255,255,255,255
OK

I haven't verified that it actually works, but the output is encouraging.

2 Likes

@dtaht is this the right way to disable everything but the BE queue? You said you recommended to do that with fq_codel'd WiFi.