I'm trying to use SQM (with cake/piece_of_cake.qos) on two different low-bandwidth lines at different locations.
One is a 802.11h HaLow-link at ~500kbps shared media, the other one is a G3-PLC link with 64 kbps net rate (also shared media).
One (solved?) problem was the shared media, there seems to be no proper way to configure SQM explicitely for a half-duplex link if you like. Disabling ingres shaping solved that so some extend, at least better than egress shaping on the other end of the link or local egress (close to unusable).
Yet the link speed varies from "quite ok" to "not usable at all" at times. I'm currently not sure if the link quality itself has much to do with it, as even if a HTTP upload (resp. GET from behind the link) barfs, a concurrent SSH connection works like a charm.
A simple queueing/shaping like fq_codel is worse however.
Does anyone has good experience with such extreme low-bandwidth, error-prone links and would share his configuration?
Bandwidth on the HaLow link (802.11ah) is dependant on allowed air time and a number of other parameters, but basically yes, it changes over time, is error-prone (in terms of packet loss) and is half-duplex shared medium. Similar for the G3-PLC, wire-bound but also shared media and packet loss.
What is very strange and I do not understand: after a router reboot, the whole thing seems to work as expected. Only after a day or two, the sqm starts to not behave well.
The specifics surrounding the connections would be better addressed by @moeller0, but concerning the variable bandwidth aspect, this creates a challenge because cake works with a fixed bandwidth (albeit that fixed bandwidth can be regularly updated using appropriate tc calls). So I presume that you should use something like cake-autorate or equivalent to constantly adjust the bandwidth as required. I don’t think I’ve seen cake-autorate operate at such low bandwidths before.
Given the specific requirements around HaLow, I don't think autorate is an option here - just because of the very limited bandwidth and the airtime limits (meaning you're wasting valuable airtime for the tuning, which would be needed for more important data). Let's reconsider what HaLow is, very low and volatile bitrate, long range (kilometres) - and with that long range many concurrent users in sight competing for the same bitrate. I'd go as far as venturing that if latency is an issue, you're using the wrong technology here. HaLow is supposed to transmit short datagrams, sensor data and similar, not to transmit audio/ video.
Such low data rates put you deeply into the territory of "pain" if you start using greedy/capacity seeking protocols over these... serialization delay for a full sized packet alone is around:
500Kbps: (15388)/(5001000)1000 = 24.608 milliseconds
64Kbps: (15388)/(64*1000)*1000 = 192.25 milliseconds
So make sure your target is large enough (also consider MSS clamping on the 64 link, if you actually use TCP). That said, cake will (for good reasons) always allow 2 packets per flow, which at 64 Kbps is pretty terrible.
I would probably not bother with autorate here, at 64 Kbps the measurement traffic alone is going to be measurable. Maybe set a traffic shaper to some optimistic value (e.g. 450 and 60) and configure a large enough target for each (36 seconds for the first, 200ms for the second) and just accept that unless you tightly control the traffic sources you will be in a world of pain...
Maybe try to tune down TCP aggressively, e.g. small receive buffers.
Regarding HaLow, in this case is just a point-to-point connection, the problem with 100Mbps ethernet from behind the link going down to some kbps is just the use case for buffer bloat, isn't it? As I mentioned, simple queueing with fq_codel didn't work out either.
Possible, it depends on how quickly the achievable capacity changes... but a single ping packet is as ethernet frame 102 bytes and has a serialisation time of:
(1028)/(641000)*1000 = 12.75 Milliseconds
not totally terrible but not great either.
Are these time critical in any way or could you just do this via curl with the --limit-rate argument? to reign it in a bit?
Also instead of pure ssh maybe try mosh, it can do wonders on such links and feel pretty snappy.
I did some more testing, and found an interim solution to just use a tcp relay (socat). So terminating tcp traffic and relaying works quite well, just like I can comfortably work using ssh while (routed) http traffic barfs at the same time.
Here's a transscript of routed http traffic, stopped after several minutes:
--2026-06-09 09:32:52-- http://172.23.118.161/data/260609/int_ana_260609.txt
Verbindungsaufbau zu 172.23.118.161:80... verbunden.
HTTP-Anforderung gesendet, warte auf Antwort... 200 Document follows
Länge: 749 [text/plain]
In »»172.23.118.161/data/260609/int_ana_260609.txt«« speichern.
172.23.118.161/data/260609/int_ana_2 100%[========================================================================>] 749 749 B/s in 9,5s
2026-06-09 09:33:02 (78,5 B/s) - »»172.23.118.161/data/260609/int_ana_260609.txt«« gespeichert [749/749]
--2026-06-09 09:33:02-- http://172.23.118.161/data/260609/int_sma_260609.txt
Wiederverwendung der bestehenden Verbindung zu 172.23.118.161:80.
HTTP-Anforderung gesendet, warte auf Antwort... Keine Daten empfangen.
Erneuter Versuch.
--2026-06-09 09:33:03-- (Versuch: 2) http://172.23.118.161/data/260609/int_sma_260609.txt
Verbindungsaufbau zu 172.23.118.161:80... verbunden.
HTTP-Anforderung gesendet, warte auf Antwort... 200 Document follows
Länge: 62501 (61K) [text/plain]
In »»172.23.118.161/data/260609/int_sma_260609.txt«« speichern.
.118.161/data/260609/int_sma_260609. 3%[=> ] 2,00K --.-KB/s eta 23m 54s
[...]
18.161/data/260609/int_sma_260609.tx 16%[==========> ] 10,00K 706 B/s eta 6m 19ss
172.23.118.161/data/260609/int_sma_2 18%[============> ] 11,24K 1,24KB/s in 1m 49s s
2026-06-09 09:34:59 (105 B/s) - Verbindung bei Byte 11506 geschlossen. Erneuter Versuch.
--2026-06-09 09:35:01-- (Versuch: 3) http://172.23.118.161/data/260609/int_sma_260609.txt
Verbindungsaufbau zu 172.23.118.161:80... verbunden.
HTTP-Anforderung gesendet, warte auf Antwort... 200 Document follows
Länge: 62501 (61K) [text/plain]
In »»172.23.118.161/data/260609/int_sma_260609.txt«« speichern.
.118.161/data/260609/int_sma_260609. 3%[=> ] 2,00K 178 B/s eta 7m 9s
While relayed works fine within 19 sec...
--2026-06-09 10:21:31-- http://172.23.118.14:81/data/260609/int_ana_260609.txt
Verbindungsaufbau zu 172.23.118.14:81... verbunden.
HTTP-Anforderung gesendet, warte auf Antwort... 200 Document follows
Länge: 803 [text/plain]
In »»172.23.118.14:81/data/260609/int_ana_260609.txt«« speichern.
172.23.118.14:81/data/260609/int_ana 100%[========================================================================>] 803 --.-KB/s in 0,07s
2026-06-09 10:21:33 (10,8 KB/s) - »»172.23.118.14:81/data/260609/int_ana_260609.txt«« gespeichert [803/803]
--2026-06-09 10:21:33-- http://172.23.118.14:81/data/260609/int_sma_260609.txt
Verbindungsaufbau zu 172.23.118.14:81... verbunden.
HTTP-Anforderung gesendet, warte auf Antwort... 200 Document follows
Länge: 69452 (68K) [text/plain]
In »»172.23.118.14:81/data/260609/int_sma_260609.txt«« speichern.
172.23.118.14:81/data/260609/int_sma 100%[========================================================================>] 67,82K 4,43KB/s in 15s
2026-06-09 10:21:49 (4,43 KB/s) - »»172.23.118.14:81/data/260609/int_sma_260609.txt«« gespeichert [69452/69452]
BEENDET --2026-06-09 10:21:50--
Verstrichene Zeit: 19s
Geholt: 2 Dateien, 69K in 15s (4,46 KB/s)
So either my setup has some severe problems (there is a bridge on wan side and dnat on the lan side involved) or this together with sqm fails somehow on these link characteristics.
sqm alone seems to work fine as the relaying case showed.
What I can also think of is an unexpected behaviour of the tcp stack on the web server side (some embedded windows from 2008/2009).
So a TCP proxy alone helps? Or did you combine that proxy with sqm? Anyway the fact that this help at least mildly implies that "some embedded windows from 2008/2009" might have default TCP tuning that is all but optimal for your Links... honestly not all that surprising TCP tuning is tricky and if the stack does not properly auto-tune you will likely feel some pain outside the parameter space microsoft tuned the stack for.
One small thing I would test separately: your wget log shows the second request first tries to reuse the existing HTTP connection. If the relay helps mostly because it terminates TCP, try forcing short/fresh HTTP sessions and a capped client rate, e.g. wget --no-http-keep-alive --limit-rate=... or curl --no-keepalive --limit-rate .... If that changes the failure pattern, it points more at TCP/window/keepalive behaviour of the endpoint than at SQM itself. It won't fix airtime, but it gives a cleaner test before changing qdisc params.
Yes, thanks! Forgot to mention, I did this exactly during the tests which resulted in relay usage, neither rate limiting on the client nor disabling keep-alive changed anything.
Yes, sqm was/is still in place, together with the tcp relay it works fine. Didn't test with relay only, though.
If I find the time, I can rebuild this test case in lab with more up-to-date nodes. Did I mention there are three wireless backhaul hops, an lte uplink plus openvpn included in the path
However, the whole topology does not pose any problem for the other nodes in this complex network except for the particular node with last hop over 802.11ah.