TP6: CAKE gebaut -- und der Bau beweist, dass der CRS326 keine Queue fuehrt

Entscheidung dieser Sitzung war "bauen statt schliessen". Gebaut ist es. Das
Ergebnis stellt TP6 aber neu: die Queue steht, ist compliant, und tut nichts.

DREI BELEGE AM GERAET, unabhaengig voneinander:
  /queue tree nach 6 MB echtem Client-Upload   ->      0 Bytes
  Simple Queue auf 10.40.0.0/16 (Gegenprobe)   ->      0 Bytes
  Upload gegen cake-bandwidth=8.5Mbps          -> 9,48 Mbit

Der dritte ist der harte. Ein Zaehler auf 0 laesst sich als Anzeigeproblem
wegerklaeren, ein Durchsatz UEBER dem gesetzten Limit nicht.

URSACHE (sehr wahrscheinlich, nicht abschliessend bewiesen): CRS326 mit
Marvell-98DX3236. Bridge faehrt hw-offload, alle Ports only-hardware-queue,
Bridge-Interface no-queue. Der Switch-Chip serialisiert, nicht die CPU. Dass
l3-hw-offloading=no ist, widerspricht dem nicht: die CPU routet (Firewall zaehlt
32,9 Mio Pakete), aber sie serialisiert nicht.

WAS BESTAND HAT -- die ComplianceRule `queue`:
  - nautobot/ingest-queue-rule.py (idempotent, Dry-Run default)
  - match_config = "/queue type\n/queue tree"; /queue interface bewusst NICHT,
    das traegt nur die Default-Portzuordnung und hat mit QoS nichts zu tun
  - Wirksamkeit bewiesen, nicht behauptet: erst 99/100 mit exakt der fehlenden
    Queue als `missing`, nach dem Deploy 100/100, 0 Drifts
  - Zaehler jetzt 25 Rules x 4 Geraete = 100 Checks
Damit ist dieselbe blinde Stelle zu, die TP26 fuer /ip firewall filter geschlossen
hat -- und zwar VOR der Queue, wie Runbook 4.1 es verlangt.

ZWEI DESIGN-ENTSCHEIDUNGEN, die im Template begruendet stehen:
  - nur die Senderichtung: der Download liegt mit +23..28 ms UNTER der
    3-Schwelle und ist nach demselben Kriterium Fall A
  - parent=vlan100 statt target=10.40.0.0/16: eine Simple Queue aufs LAN-Supernetz
    haette Inter-VLAN (NAS <-> MAIN, geroutet ueber dieselbe CPU) mitgedrosselt

VIER SACKGASSEN, dokumentiert in ref_crs326_keine_software_queue:
  1. active-queue=queue-tree heisst nur "verdrahtet", nicht "wirksam"
  2. parent=global OHNE packet-mark faengt per Definition nichts
  3. target=0.0.0.0/0 wird stillschweigend zu target="" verworfen
  4. router-eigener Verkehr durchlaeuft die Queues nicht -- Test-Pings vom Router
     beweisen nichts, es braucht einen echten LAN-Client
Zwei davon sahen wie Hardware-Befunde aus und waren eigene Testfehler.

FORMATFALLE: RouterOS exportiert 8.5Mbps statt 8500000 und schiebt eine eigene
Hinweiszeile vor die Tree-Zeile, wodurch der Backup-Normalisierer /queue tree
nicht abflacht. Template baut beides nach -> 100/100.

Alle Testaenderungen liefen als Config-Transaktion und sind zurueckgebaut; keine
Akte offen. Die wirkungslose Queue bleibt vorerst am Geraet und in der SoT --
dokumentiert, nicht als aktives QoS misszuverstehen -- bis ueber die drei Wege
entschieden ist (hw-offload opfern / Chip-QoS ohne CAKE / TP6 schliessen).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 00:54:21 +02:00
parent e9a22c8277
commit 2048b77f8f
10 changed files with 299 additions and 4 deletions

View File

@@ -52,8 +52,8 @@ ab jetzt bei jeder Änderung mitgezogen, nicht nur die TP-Abschnitte.)*
08-18) — TP19 ist geschlossen; `cudy1` hängt stromlos an core `ether11`, physischer Ausbau ist hands-on.
- **Kontrolle / Governance:** MikroMCP für Reads/Debug (alle 4 Geräte in der Registry),
**Config-Änderungen ausschließlich über Nautobot Golden Config** (TP21/TP22 — Deploy-Pipeline scharf,
**96/96 Compliance-Checks grün, 0 Drifts** bei **24 Rules × 4 Geräten**, Stand 2026-08-23 —
neu dazu: **`wifi-access-list`**, s. TP22-Nachtrag).
**100/100 Compliance-Checks grün, 0 Drifts** bei **25 Rules × 4 Geräten**, Stand 2026-08-23 —
neu dazu: **`wifi-access-list`** (08-22) und **`queue`** (08-23, TP6), s. TP22-Nachtrag).
<details><summary>📜 Historische Fassung (Stand bis 2026-08-08, Topologie <b>vor</b> dem Core-Cutover — bewusst erhalten, nicht als Ist lesen)</summary>
@@ -421,7 +421,53 @@ FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
- **(b) Live-Torch als Ad-hoc-Observability:** DNS ist bei direktem 1.1.1.1 blind, **Flows nicht** (NATen über ap1). `torch` auf `vlan30`/`vlan50` gefiltert auf die Geräte-IP zeigt Ziel-IPs live (Versuni → AWS `eu-west-1` IoT erkennbar). Voraussetzung: Gerät aktiv. Merkregel: Airfryer nur online wenn er kocht → Capture ans Einschalten koppeln.
- **Abh.:** UNTRUSTED-Move des Airfryers (Kandidat, s. VLAN50) + TP5-Deny-by-default. Kein Blocker.
### TP6 — QoS/CAKE + Call-Quality-A/B-Test ▸ 🟡 **GEMESSEN 2026-08-20/21 — Fall B, aber „messbar, nicht hörbar"**
### TP6 — QoS/CAKE + Call-Quality-A/B-Test ▸ 🔴 **GEBAUT 2026-08-23 — UND NACHWEISLICH WIRKUNGSLOS. Der CRS326 fuehrt keine Software-Queue.**
> 🔴 **Der Befund, der TP6 neu stellt (2026-08-23):** CAKE ist gebaut, deployt und compliant
> (100/100) — **und es passiert nichts.** Drei unabhaengige Belege am Geraet:
>
> | Beleg | erwartet | gemessen |
> |---|---|---|
> | `/queue tree` Zaehler nach 6 MB Client-Upload | > 0 Bytes | **0 Bytes** |
> | Simple Queue auf `10.40.0.0/16` (Gegenprobe) | > 0 Bytes | **0 Bytes** |
> | Upload-Durchsatz gegen `cake-bandwidth=8.5Mbps` | <= 8,5 Mbit | **9,48 Mbit** |
>
> Der dritte ist der harte: die Queue **drosselt nicht**, sie zaehlt nicht, sie wirkt nicht.
> Das ist kein Zaehler-Anzeigeproblem, sondern die Sache selbst.
>
> **Sehr wahrscheinliche Ursache (nicht abschliessend bewiesen):** `crs326-core` ist ein
> **CRS326 mit Marvell-98DX3236-Switch-Chip**. Die Bridge faehrt `hw-offload` (`H`-Flag auf
> ether16), **alle** Ports stehen auf `only-hardware-queue`, das Bridge-Interface auf
> `no-queue`. Ein Geraet, dessen Ports der Switch-Chip bedient, hat an dieser Stelle keine
> Software-Queue, in der ein Scheduler arbeiten koennte. Passend dazu: `l3-hw-offloading=no`
> und `qos-hw-offloading=no` — die CPU *routet* zwar (die Firewall zaehlt 32,9 Mio Pakete),
> aber die Serialisierung passiert im Chip.
>
> 🔎 **Kontrollen, die ausgeschlossen sind:** kein WARP auf dem Testclient (Default-Route
> `10.40.20.1`, en0); der Verkehr lief ueber den Core; Fasttrack ist ohnehin tot (0 von 445).
> Zwei eigene Testfehler sind dokumentiert und korrigiert: ein `parent=global`-Tree **ohne**
> `packet-mark` faengt per Definition nichts, und `target=0.0.0.0/0` wird von RouterOS
> stillschweigend zu `target=""` verworfen — beide sahen wie Befunde aus und waren keine.
>
> ⚖️ **Damit ist die offene Frage nicht mehr „lohnt CAKE“, sondern „geht CAKE auf dieser
> Hardware ueberhaupt“.** Drei Wege, keiner geschenkt:
> 1. **`hw-offload` auf dem WAN-Pfad abschalten** — dann sieht die CPU den Verkehr und die
> Queue greift. Preis: der Switch-Chip faellt fuer diesen Pfad aus, die 800-MHz-CPU traegt
> ihn allein. Bei 9,6 Mbit WAN plausibel, **aber die Inter-VLAN-Messung dazu steht bis
> heute aus** (dieselbe offene Messung wie in §4.2 zu Fasttrack).
> 2. **QoS auf den Switch-Chip legen** (`qos-hw-offloading`) — kann Priorisierung, **kein
> CAKE**. Waere ein anderes, aermeres Werkzeug.
> 3. **TP6 schliessen** — mit dem staerksten Argument, das es je hatte: nicht nur „messbar,
> nicht hoerbar“, sondern „auf dieser Hardware nicht ohne Gegenleistung baubar“.
>
> ✅ **Was aus diesem Anlauf bleibt und Bestand hat:** die **ComplianceRule `queue`**
> (Feature + Rule, `match_config` = `/queue type` + `/queue tree`) schliesst die blinde
> Stelle aus §4.1 — dieselbe, die TP26 fuer `/ip firewall filter` geschlossen hat. Sie hat
> sich sofort bewiesen: erst 99/100 mit exakt der fehlenden Queue als `missing`, nach dem
> Deploy 100/100. Der Zaehler steht jetzt bei **25 Rules x 4 Geraeten = 100 Checks**.
> Die Queue selbst steht am Geraet und in der SoT — **wirkungslos, aber dokumentiert**, bis
> ueber die drei Wege oben entschieden ist. Sie NICHT fuer aktives QoS halten.
*(Vorheriger Kopf, als Messbefund weiter gueltig:)* 🟡 **GEMESSEN 2026-08-20/21 — Fall B, aber „messbar, nicht hörbar"**
> ✅ **Die Prämisse ist geprüft. Ergebnis + Rohdaten: [`tp6-praemisse-messrunbook.md`](tp6-praemisse-messrunbook.md) §5.**
>
> | | idle / C0 | Upload-Last | Download-Last |
@@ -1962,6 +2008,15 @@ TP5 E1 ✅ ─► E2 ✅ ─► E2-Nachtrag ✅ ─► E3 Drop ✅ ─► E4 inp
> nächste Sitzung entscheidet daher **bauen oder begründet schließen** — sie misst nicht neu.
> Übergabe mit den Sitzungszuschnitten: [`handoff-20260822-naechste-schritte.md`](handoff-20260822-naechste-schritte.md).
> 🔴 **Update 2026-08-23: die Entscheidung ist gefallen — gebaut — und der Bau hat die
> Frage veraendert.** CAKE steht auf `crs326-core` (ComplianceRule `queue` + Template-Block,
> 100/100 compliant) und ist **nachweislich wirkungslos**: 0 Bytes in der Queue nach 6 MB
> Client-Upload, und 9,48 Mbit Durchsatz gegen ein 8,5-Mbit-Limit. Ursache sehr wahrscheinlich
> die **Switch-Chip-Architektur** des CRS326 (Bridge-`hw-offload`, alle Ports
> `only-hardware-queue`). **TP6 steht damit weiter auf dem Pfad**, aber die offene Frage ist
> jetzt eine Hardware-Abwaegung (`hw-offload` opfern? Chip-QoS? schliessen?) und keine
> Nutzenfrage mehr. Details und die drei Wege: TP6-Abschnitt oben.
**TP5 ist am 2026-08-18 abgeschlossen.** Damit steht rechnerisch nur noch **TP6** auf dem kritischen Pfad —
🟠 **aber dessen Prämisse ist offen**: eine Messung von 2026-06-16 (`docs/call-quality-diagnosis.md`)
bescheinigt dem Netz bereits **A/A+** und hält CAKE für „marginal". Der nächste Schritt ist deshalb ein
@@ -1977,7 +2032,7 @@ Ziel ist. Alles andere läuft nebenher und blockiert nichts.
Anlernen eines IoT-Geraets (User 2026-08-17). Wer im IOT-SSID sitzt, ist im selben VLAN wie das
Geraet und beruehrt die `forward`-Kette gar nicht; fuer Ad-hoc-Zugriffe aus MAIN gibt es jetzt die
selbstverfallende Gruppe `jit-admin`.
2. 🟠 **TP6 — QoS/CAKE + Call-Quality-A/B-Test.** ~~Das eigentliche Projektziel; **keine offenen Blocker mehr**.~~
2. 🔴 **TP6 — QoS/CAKE + Call-Quality-A/B-Test.** **Stand 2026-08-23: gebaut, aber wirkungslos** (s. TP6-Abschnitt — Switch-Chip-Befund). Der naechste Schritt ist weder Messen noch Bauen, sondern die Entscheidung ueber `hw-offload`. ~~Das eigentliche Projektziel; **keine offenen Blocker mehr**.~~
**Korrigiert 2026-08-19:** kein *Blocker*, aber eine offene **Prämisse** — der Satz oben und dieser
Punkt widersprachen sich seit dem 18. Richtig ist: der nächste Schritt ist eine **Messung**, kein Bau.
Runbook liegt bereit: `docs/tp6-praemisse-messrunbook.md`. Fällt sie A/A+ aus, wird TP6 **geschlossen

View File

@@ -0,0 +1,16 @@
{
"change_id": "TEST-cake-parameter-probe",
"device": "crs326-core",
"scope": "queue",
"match_config": [
"/queue type",
"/queue tree"
],
"reason": "TP6: CAKE-Parameternamen und Defaults am Geraet auslesen statt raten (Type ohne Queue-Tree = wirkungslos)",
"started": "2026-08-23",
"expires": "2026-08-24",
"state": "rolledback",
"snapshot": "docs/transaktionen/TEST-cake-parameter-probe.snapshot.rsc",
"device_backup": "",
"closed": "2026-08-23"
}

View File

@@ -0,0 +1,6 @@
# Rueckbau-VORSCHLAG fuer TEST-cake-parameter-probe (crs326-core, Scope queue)
# Aus dem Snapshot vom 2026-08-23. NICHT ungeprueft deployen:
# `add`-Zeilen legen neu an, statt zu aendern — was hier gebraucht wird,
# ist in der Regel ein `set [find ...]`. Zeilen entsprechend anpassen.

View File

@@ -0,0 +1,4 @@
# Snapshot des Scopes 'queue' auf crs326-core, 2026-08-23 (Transaktion TEST-cake-parameter-probe)
# Bewusst NUR dieser Abschnitt — der Vollexport gehoert nicht ins Repo.

View File

@@ -0,0 +1,2 @@
/queue simple remove [find where name="probelan"]
/queue tree remove [find where name="probeglobal"]

View File

@@ -0,0 +1,16 @@
{
"change_id": "TEST-queue-global-zaehlprobe",
"device": "crs326-core",
"scope": "queue",
"match_config": [
"/queue type",
"/queue tree"
],
"reason": "TP6: prueft, ob parent=global auf dem CRS326 ueberhaupt zaehlt (queue=default, KEIN Limit, drosselt nichts)",
"started": "2026-08-23",
"expires": "2026-08-24",
"state": "rolledback",
"snapshot": "docs/transaktionen/TEST-queue-global-zaehlprobe.snapshot.rsc",
"device_backup": "",
"closed": "2026-08-23"
}

View File

@@ -0,0 +1,11 @@
# Rueckbau-VORSCHLAG fuer TEST-queue-global-zaehlprobe (crs326-core, Scope queue)
# Aus dem Snapshot vom 2026-08-23. NICHT ungeprueft deployen:
# `add`-Zeilen legen neu an, statt zu aendern — was hier gebraucht wird,
# ist in der Regel ein `set [find ...]`. Zeilen entsprechend anpassen.
/queue type
add cake-bandwidth=8.5Mbps cake-diffserv=diffserv4 cake-nat=yes kind=cake \
name=cake-wan-up
/queue tree
add comment="TP6: CAKE auf der Senderichtung (WAN-Egress)" name=qos-wan-up \
parent=vlan100 queue=cake-wan-up

View File

@@ -0,0 +1,9 @@
# Snapshot des Scopes 'queue' auf crs326-core, 2026-08-23 (Transaktion TEST-queue-global-zaehlprobe)
# Bewusst NUR dieser Abschnitt — der Vollexport gehoert nicht ins Repo.
/queue type
add cake-bandwidth=8.5Mbps cake-diffserv=diffserv4 cake-nat=yes kind=cake \
name=cake-wan-up
/queue tree
add comment="TP6: CAKE auf der Senderichtung (WAN-Egress)" name=qos-wan-up \
parent=vlan100 queue=cake-wan-up

129
nautobot/ingest-queue-rule.py Executable file
View File

@@ -0,0 +1,129 @@
#!/usr/bin/env python3
"""
ComplianceRule `queue` anlegen (idempotent).
Die Luecke, die das schliesst
-----------------------------
`nautobot/mikrotik_routeros.j2` hatte bis 2026-08-23 **keinen `/queue`-Block**, und
es gab keine ComplianceRule dafuer. Eine von Hand gesetzte CAKE-Queue waere damit
**unsichtbar fuer die Compliance** gewesen (sie meldet weiter "compliant", waehrend
die Queue driftet) und beim naechsten Deploy **nicht geschuetzt**.
Das ist exakt dieselbe blinde Stelle, die **TP26** fuer `/ip firewall filter`
geschlossen hat -- dort war sie 25 Firewallregeln gross.
TP6 baut jetzt genau dorthin: CAKE auf der Senderichtung (`/queue tree` auf
`vlan100`, Type aus `/queue type`). Die Regel kommt deshalb VOR der Queue, nicht
danach -- so, wie es `tp6-praemisse-messrunbook.md` §4.1 verlangt.
Warum zwei Praefixe und nicht `/queue`
--------------------------------------
`/queue interface` traegt die Default-Zuordnung aller 26 Ports
(`only-hardware-queue`) und `bridge=no-queue`. Die stehen zwar heute in keinem
Backup (RouterOS exportiert Defaults nicht), aber ein Praefix `/queue` wuerde sie
mitfangen, sobald sich daran je etwas aendert -- und das hat mit QoS nichts zu tun.
Gematcht wird deshalb nur, was TP6 tatsaechlich setzt.
export NAUTOBOT_TOKEN=... # aus docs/nas-vlan20/stacks/210-nautobot.yml
python3 nautobot/ingest-queue-rule.py # Dry-Run
python3 nautobot/ingest-queue-rule.py --apply
"""
import json
import os
import sys
import urllib.error
import urllib.parse
import urllib.request
BASE = "http://10.40.20.30:8080/api"
TOKEN = os.environ.get("NAUTOBOT_TOKEN", "")
APPLY = "--apply" in sys.argv
FEATURE = "queue"
BESCHREIBUNG = ("TP6 QoS/CAKE: Queue-Types und Queue-Tree. Vor 2026-08-23 stand "
"/queue unter keiner Rule -- eine handgesetzte Queue waere unsichtbar "
"gedriftet. Analog zu TP26 fuer /ip firewall filter.")
MATCH = "/queue type\n/queue tree"
PLATTFORM = "RouterOS"
def req(method, path, data=None):
url = path if path.startswith("http") else BASE + path
body = json.dumps(data).encode() if data is not None else None
r = urllib.request.Request(url, data=body, method=method)
r.add_header("Authorization", "Token " + TOKEN)
r.add_header("Content-Type", "application/json")
r.add_header("Accept", "application/json")
try:
with urllib.request.urlopen(r, timeout=60) as resp:
raw = resp.read()
return json.loads(raw) if raw else {}
except urllib.error.HTTPError as e:
# 🔴 Fehlerkoerper ausgeben: Nautobot begruendet 400er praezise, und ohne den
# Text raet man an Feldnamen herum (TP22-Erfahrung).
sys.exit("!! %s %s -> %s\n %s" % (method, url, e.code, e.read().decode()[:600]))
def eins(pfad, **filter):
q = urllib.parse.urlencode(filter)
res = req("GET", "%s?%s" % (pfad, q)).get("results", [])
if len(res) > 1:
sys.exit("FEHLER: %s?%s liefert %d Treffer, erwartet 0 oder 1" % (pfad, q, len(res)))
return res[0] if res else None
def main():
if not TOKEN:
sys.exit("NAUTOBOT_TOKEN fehlt.")
print("Modus:", "APPLY" if APPLY else "DRY-RUN (nichts wird geschrieben)")
plat = eins("/dcim/platforms/", name=PLATTFORM)
if not plat:
sys.exit("Plattform %r nicht gefunden." % PLATTFORM)
print("Plattform : %s (%s)" % (plat["display"], plat["id"]))
feat = eins("/plugins/golden-config/compliance-feature/", name=FEATURE)
if feat:
print("Feature : existiert bereits (%s)" % feat["id"])
else:
print("Feature : anlegen -> %s" % FEATURE)
if APPLY:
feat = req("POST", "/plugins/golden-config/compliance-feature/",
{"name": FEATURE, "slug": FEATURE, "description": BESCHREIBUNG})
print(" angelegt (%s)" % feat["id"])
if not feat:
print("\nDry-Run: ohne Feature kann die Rule nicht geprueft werden. Mit --apply erneut.")
return
rule = eins("/plugins/golden-config/compliance-rule/",
feature=feat["id"], platform=plat["id"])
if rule:
print("Rule : existiert bereits (%s), match_config=%r"
% (rule["id"], rule.get("match_config")))
if rule.get("match_config") != MATCH:
print(" ⚠️ match_config weicht ab -- erwartet %r" % MATCH)
return
nutzlast = {
"feature": feat["id"],
"platform": plat["id"],
"description": BESCHREIBUNG,
# Reihenfolge ist hier bedeutungslos: Queue-Trees haengen ueber `parent=`
# am Namen, nicht an der Position. Anders als /ip firewall filter.
"config_ordered": False,
"config_type": "cli",
"match_config": MATCH,
"custom_compliance": False,
"config_remediation": False,
}
print("Rule : anlegen -> %s auf %s, match_config=%r" % (FEATURE, PLATTFORM, MATCH))
if APPLY:
r = req("POST", "/plugins/golden-config/compliance-rule/", nutzlast)
print(" angelegt (%s)" % r["id"])
else:
print(" Nutzlast: %s" % json.dumps(nutzlast))
if __name__ == "__main__":
main()

View File

@@ -287,6 +287,53 @@
/interface wireguard peers add allowed-address=0.0.0.0/0 comment="TP16.1 CF-PoP" endpoint-address=162.159.193.2 endpoint-port=2408 interface=cf-mesh name=cf-pop persistent-keepalive=25s public-key="bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo="
/ip address add address=100.96.0.6 comment="TP16.1 Mesh-Overlay" interface=cf-mesh network=100.96.0.6
/ip route add comment="TP16.1 Mesh" disabled=no distance=1 dst-address=100.96.0.0/12 gateway=cf-mesh
# [11] QoS / CAKE (TP6, 2026-08-23) — gebaut gegen eine Zahl, nicht gegen ein Ritual.
#
# GEMESSEN am 2026-08-20/21 (tp6-praemisse-messrunbook.md §5), Linerate erstmals
# dokumentiert: Upload 9,6 Mbit, Download 54,6 Mbit.
#
# idle Upload-Last Download-Last
# Durchlauf 1 12,9 ms 60,4 ms 41,3 ms
# Referenz 06-16 12 ms 17,5 ms nie gemessen
#
# Der Anstieg liegt in der SENDERICHTUNG bei +28..+47 ms und damit ueber der
# §3-Schwelle von <=30 ms -> Fall B. Der Download liegt mit +23..+28 ms DARUNTER
# und ist damit nach demselben Kriterium Fall A.
#
# 🔴 Deshalb wird hier NUR die Senderichtung geshaped. Das ist keine Sparsamkeit,
# sondern dasselbe Abbruchkriterium in beide Richtungen angewandt: eine Queue fuer
# den Download waere gegen ein Problem gebaut, das die Messung nicht gezeigt hat.
# Ingress-Shaping kostet auf RouterOS ausserdem Mangle-Umwege, weil man die
# Gegenstelle nicht kontrolliert -- Aufwand fuer einen unbelegten Nutzen.
#
# 🔴 parent=vlan100, NICHT target=10.40.0.0/16. Eine simple queue auf das
# LAN-Supernetz wuerde auch INTER-VLAN-Verkehr erfassen (NAS <-> MAIN laeuft
# geroutet ueber dieselbe CPU) und ihn auf WAN-Tempo drosseln. vlan100 traegt
# ausschliesslich WAN-Verkehr, der Rest bleibt unberuehrt.
#
# Bandbreite = 8,5 Mbit ~= 88 % der gemessenen 9,6. CAKE muss die Warteschlange
# selbst halten koennen; bleibt der Puffer beim ISP, regelt es nichts. Der Preis
# sind ~1,1 Mbit Spitzendurchsatz und er ist im A/B-Nachweis sichtbar.
#
# cake-nat=yes ist hier kein Beiwerk: hinter srcnat saehe CAKE sonst nur EINE
# Adresse und koennte die Hosts nicht gegeneinander fair halten -- genau das ist
# aber der Zielfall ("jemand laedt hoch, waehrend jemand telefoniert").
# cake-diffserv=diffserv4 trennt dabei latenzkritisch von bulk.
#
# ⚠️ Fasttrack ist auf diesem Geraet faktisch tot (accept steht vor fasttrack,
# 0 von 445 Verbindungen) und BLEIBT es -- Entscheid 2026-08-19, §4.2. Fasttrack
# umgeht Queues; fuer CAKE ist der Zustand die guenstigere Ausgangslage. Wer die
# Regelreihenfolge je "repariert", setzt diese Queue mit ausser Kraft.
# ⚠️ FORMAT: RouterOS exportiert `cake-bandwidth=8.5Mbps`, nicht `8500000` (gleiche
# Klasse wie `hw-offload=true` vs `yes`), UND schiebt vor die Tree-Zeile eine eigene
# Hinweiszeile. Dadurch flacht der Backup-Normalisierer `/queue tree` nicht ab: die
# add-Zeile steht ohne Pfad-Praefix da. Beide Eigenheiten muessen hier nachgebaut
# werden, sonst meldet die Compliance einen Dauer-Drift, bei dem das GERAET recht hat.
/queue type add cake-bandwidth=8.5Mbps cake-diffserv=diffserv4 cake-nat=yes kind=cake name=cake-wan-up
/queue tree
# CAKE type with bandwidth setting detected, configure traffic limits within queue itself
add comment="TP6: CAKE auf der Senderichtung (WAN-Egress)" name=qos-wan-up parent=vlan100 queue=cake-wan-up
{% elif obj.role.name == "Switch" %}
# =====================================================================================
# L2-Switch (crs326-branch) — Sollzustand des Mgmt-Layers.