Stratum

A QoS substrate composing DiffServ, L4S, and CAKE in ns-3
Categories: Traffic control

Stratum: one composer, four pluggable slots, three clients

Stratum is a QoS substrate for ns-3: a single composer with four pluggable strategy slots, on which DiffServ, L4S, and CAKE are expressed as three clients, each selecting one strategy per slot. Any node — edge or core — can be configured as any of the three, so one ns-3 module covers class-aware queueing (DiffServ), low-latency AQM (L4S), and per-flow isolation (CAKE).

Every node builds its queueing discipline from four slots, populated independently (an edge and a core node need not carry the same strategies, per RFC 2475 §2.4):

  1. Classify-and-Meter — a meter strategy plus a classifier: which traffic, and how much of it.
  2. Mark-and-Route — a DSCP tag plus a PHB (per-hop behaviour) table: how packets are labelled and steered.
  3. Per-class slot array — up to eight inner queue discs: where packets wait.
  4. Across-slot service policy — the scheduler / dispatcher: who is served next.

Three clients, one substrate

Each client selects one strategy per slot:

DiffServ (RFC 2475)

  • Classify-and-Meter: sr-TCM / tr-TCM / TSW2CM·3CM + byte-accounting
  • Mark-and-Route: DSCP + PHB table
  • Slot array: RED / RIO / drop-tail
  • Service policy: PQ · WRR · WFQ · WF2Q+ · SCFQ · SFQ · LLQ · hybrid-LLQ

L4S (RFC 9331 / 9332)

  • Classify-and-Meter: DualPI2 ECT(1) classifier
  • Mark-and-Route: DSCP + L4S identifier
  • Slot array: classic + L4 inners
  • Service policy: coupled marking probability

CAKE (sch_cake parity)

  • Classify-and-Meter: DSCP-to-tin (besteffort, precedence, diffserv3/4/8)
  • Mark-and-Route: tin assignment
  • Slot array: per-tin FqCobalt
  • Service policy: across-tin DRR + optional LLQ

Each client is a complete implementation in its own right; the substrate is what brings all three together.

Extensible by registry

External AQMs and schedulers plug in as cells in a registry template — no fork, no edits to the composer core. Downstream consumers (CLI catalogues, plot palettes, documentation tables, smoke tests) auto-derive their coverage from the registry, so adding a cell propagates everywhere without manual fan-out. In-tree today: 13 AQM cells and 9 scheduler cells.

Validation & reproducibility

17 test suites cover the three clients and RFC conformance vectors (RFC 2697 / 2698 / 2859 for metering; RFC 9331 / 9332 for L4S). The accompanying paper's figures reproduce from the source tree via scripts/reproduce-paper.sh.

Lineage

Stratum's DiffServ client derives from the author's 2001 DiffServ4NS ns-2 module (MSc thesis, University of Pisa; IEEE ISCC 2002; SourceForge 2006). The L4S and CAKE clients are new for this work.

Cite this

  • Software archive: DOI 10.5281/zenodo.20723772 — Zenodo concept DOI (always resolves to the latest release).
  • Validation dataset: DOI 10.5281/zenodo.20724063 — Zenodo concept DOI (always resolves to the latest version; covers both the host-isolation fairness and autorate-ingress cross-stack measurements).
  • Paper: under peer review; its DOI will be added here once published.
  • See also the repository's CITATION.cff.

Links

License: GPLv2.

v2.0.1

Works with ns-3.48

Build History : Stratum v2.0.1

Release Notes

<p>Stratum v2.0.1 is a patch release. No change to module behaviour, queueing, or the public API; built and tested against ns-3.48.</p> <p>Fixed: the test runner no longer emits an <code>Invalid test name</code> warning (three test-case names used a character ns-3 rejects, now renamed), and no longer leaks stray <code>Packets Statistics</code> tables to the console during a run.</p> <p>Added: <code>scripts/lint-test-names.sh</code>, a guard (run by the audit gates) that fails if any test-case name uses a character ns-3 rejects.</p> <p>Stratum v2.0.0 composes DiffServ, L4S, and CAKE as three first-class clients on a single ns-3 edge queue disc. Built and tested against ns-3.48.</p> <p><strong>This release</strong> — a feature and API release. The headline is IPv6 support across all three clients; the configuration API is reshaped onto designated-initializer structs, which retires the positional helpers and makes this a major (source-breaking) release. The queueing and AQM behaviour of existing IPv4 scenarios is unchanged. - <strong>IPv6</strong> — DiffServ, L4S, and CAKE classify, mark, meter, and shape over IPv6 as well as IPv4, through address-family-agnostic DS-field and ECN handling. New dual-stack example recipes ship for each client and for a CAKE+L4S IPv6 composition. - <strong>Preset edge composers</strong> — <code>diffserv::Helper::SetAsDiffserv</code>, <code>l4s::Helper::SetAsL4s</code>, and <code>cake::Helper::SetAsCake*</code> build a configured client edge in one call; <code>stratum::InstallRoot</code> then installs any built disc — edge or core — as a device's root queue disc. - <strong>Designated-initializer config API (breaking)</strong> — <code>ConfigQueue</code>, the meter policies, the policer entry, the meter rule, the CAKE options, and <code>MarkRule</code> now take C++23 designated-initializer structs; the positional helpers are retired. <code>MarkRule</code> address matching is typed and family-aware (exact IPv4 or IPv6). - <strong>Command-line reference</strong> — a generated handbook appendix documents every example's flags, kept honest by a drift check in the audit gate.</p> <p><strong>Composition</strong> - Four pluggable per-node slots: Classify-and-Meter, Mark-and-Route, a per-class slot array, and an across-slot service policy. Each client selects one strategy per slot.</p> <p><strong>DiffServ client</strong> — RFC 2697 (sr-TCM), RFC 2698 (tr-TCM), and TSW2CM/TSW3CM meters; DSCP classification and PHB marking with a configurable PHB table; RED / RIO / drop-tail inner queue discs; schedulers PQ, WRR, WFQ, WF2Q+, SCFQ, SFQ, LLQ, and hybrid-LLQ.</p> <p><strong>L4S client</strong> — DualPI2 coupled AQM (RFC 9332) with ECT(1) classification (RFC 9331) and coupled classic / scalable congestion marking.</p> <p><strong>CAKE client</strong> — DSCP-to-tin mapping (besteffort, precedence, diffserv3, diffserv4, diffserv8) over per-tin FqCobalt under an across-tin DRR dispatcher; host-pair isolation, ACK filtering, optional per-tin shaping, named link-layer-overhead and RTT presets, and per-tin diagnostics aligned with <code>tc -s qdisc show</code>.</p> <p><strong>Validation</strong> — 19 test suites covering the three clients, RFC conformance vectors (RFC 2697 / 2698 / 2859 / 9331 / 9332), and cross-implementation reference fixtures. The accompanying paper's figures reproduce via scripts/reproduce-paper.sh.</p> <p><strong>Requirements</strong> — a small set of ns-3 mainline patches (bundled in patches/ns3/), applied at the pinned ns-3.48 revision. See the Installation tab for the three install paths: into an existing ns-3 tree, a script-managed sibling clone, or Bake.</p>
Bakefile : Link


v1.3.0

Works with ns-3.48

Latest Build :

Build History : Stratum v1.3.0

Release Notes

<p>Correctness release: behavioural defects fixed against the primary references (RFCs, Linux <code>sch_cake.c</code>, the reference DualPI2, the fair-queueing papers), each pinned by a regression test, plus one backward-compatible option (configurable TSW window). No breaking API changes. The WFQ and L4S fixes change the output of affected simulations.</p> <h3>Schedulers</h3> <ul> <li><strong>WFQ:</strong> fixed a virtual-time blow-up after a full drain and reactivation that collapsed weighted service to strict priority (a non-integer-weight ULP residue); the weight sum is pinned to zero when the queue empties.</li> <li><strong>LLQ:</strong> the priority-lane rate cap now engages and releases correctly (the inner scheduler now observes its own departures).</li> <li><strong>Hybrid-LLQ across-tin DRR:</strong> the round-robin cursor advances off a slot that drains empty, matching the pure-DRR sibling and Linux <code>cake_dequeue</code>.</li> </ul> <h3>CAKE</h3> <ul> <li><strong>ACK filter:</strong> a data-bearing ACK, or one with an unknown/malformed/truncated TCP option, is now a valid filtering trigger, matching <code>sch_cake.c</code>.</li> <li><strong>Autorate-ingress:</strong> the rate reconfigure fires on each measurement-window close after warm-up (kernel cadence), not on a per-packet timer.</li> <li><strong>diffserv4 DSCP map (rate-based shaper):</strong> corrected four code points (DSCP 4, 10, 12, 14) to the Linux <code>diffserv4[]</code> table.</li> <li><strong>diffserv-precedence DRR weights:</strong> now follow the Linux <code>sch_cake</code> precedence quantum ladder.</li> </ul> <h3>L4S</h3> <ul> <li><strong>Dequeue-time marking:</strong> the congestion signal is applied at dequeue from each packet's own sojourn, suppressed below a two-MTU standing queue, matching the reference DualPI2.</li> <li><strong>DualPI2 controller:</strong> the proportional term uses a zero previous-queue on the first tick, matching the reference and the RFC 9332 pseudocode.</li> </ul> <h3>Meters and edge</h3> <ul> <li><strong>Flow-weighted meter:</strong> the deterministic, probabilistic, and periodic penalty modes are honoured (previously all behaved deterministically).</li> <li><strong>DSCP routing:</strong> the code-point index is masked to six bits on enqueue.</li> <li><strong>RED / RIO sub-queue:</strong> the per-precedence state array is bounds-checked on the RIO and PHB paths.</li> <li><strong>TSW meters:</strong> the averaging-window length is configurable through the helper (was fixed at one second).</li> </ul> <h3>Tests</h3> <ul> <li><strong>Host-isolation jitter-floor test:</strong> re-grounded a fragile single-replica band to the mean of five jitter replicas (behaviour unchanged).</li> </ul>
Bakefile : Link


v1.2

Works with ns-3.48

Latest Build :

Build History : Stratum v1.2

Release Notes

<p>Adds a reproducible CAKE host-fairness example and regression test, and revises the handbook. The substrate model is unchanged from v1.1.</p> <h3>Reproducibility</h3> <ul> <li><strong>CAKE host-fairness, reproducible from the module:</strong> a new example and gated regression test reproduce the per-host share and backlog occupancy directly (previously external measurement scripts).</li> </ul> <h3>Handbook</h3> <ul> <li>Tightened notation and terminology across all three parts.</li> <li>Aligned the CAKE evidence chapter with the reproducible host-fairness result; added a share-versus-throughput figure.</li> <li>Filled the deferred recipe walkthroughs and their run-time estimates.</li> </ul>
Bakefile : Link


v1.1

Works with ns-3.48

Latest Build :

Build History : Stratum v1.1

Release Notes

<p>First standalone release of the ns-3 QoS substrate composing DiffServ, L4S, and CAKE as three first-class clients of one edge queue disc, carried forward from the <a href="https://github.com/digitalities/diffserv4ns">DiffServ4NS</a> lineage (the 2001 ns-2 module and the frozen <code>v1.0-icns3-submission</code> snapshot live upstream). Built against the pinned ns-3 release (<code>scripts/fetch-ns3.sh --print-pin</code>).</p> <h3>Difference from the diffserv4ns repository</h3> <ul> <li><strong>Standalone ns-3 module:</strong> ships as a drop-in contrib module (<code>model/</code>, <code>helper/</code>, <code>test/</code>, <code>examples/</code>, <code>CMakeLists.txt</code> at the root), independent of the ns-2 sources, paper, and lineage archive.</li> <li><strong><code>ns3::stratum</code> namespace and rename:</strong> moved from <code>ns3::diffserv</code> / <code>Ds*</code> to the <code>ns3::stratum::{diffserv,l4s,cake}</code> hierarchy, with prefix-free class names, <code>stratum-</code> file names, and a <code>stratum</code> build target.</li> <li><strong>RFC 9332 L4S coupling correction:</strong> classic coupled-drop <code>p'^2</code> (was <code>(k*p')^2</code>), L4S coupled-mark <code>min(k*p', 1)</code> honouring <code>CouplingFactor</code> (was a hardcoded factor 2), PI gains at RFC defaults (<code>alpha = 0.16 Hz</code>, <code>beta = 3.2 Hz</code>); pinned by a golden vector, ECN/DSCP checks, and a three-seed fairness-parity gate.</li> <li><strong>CAKE fidelity corrections:</strong> Linux-verbatim DSCP-to-tin maps; diffserv3 Latency-Sensitive share on the kernel quantum ladder; <code>SetBandwidth</code> via a compose-time profile record; host-pair isolation across the sparse-to-bulk transition; IPv6 ACK-filter parity; a byte-exact autorate-ingress estimator.</li> <li><strong>Scheduler and harness corrections:</strong> corrected WF2Q+ / PQ attributions and round-robin docs; spec-tier gates and a classic-lane collapse fix in the multi-AQM harness; a buffer-adequate host-isolation gate.</li> </ul> <h3>Substrate</h3> <p>Four pluggable per-node primitives — Classify-and-Meter, Mark-and-Route, a per-class slot array, and an across-slot service policy — let each client build a queueing discipline by selecting one strategy per stage.</p> <h3>DiffServ client</h3> <ul> <li>RFC 2697 (sr-TCM), RFC 2698 (tr-TCM), and TSW2CM/TSW3CM meters.</li> <li>DSCP classification and PHB marking with a configurable PHB table.</li> <li>RED / RIO / drop-tail inner queue discs.</li> <li>Schedulers: PQ, WRR, WFQ, WF2Q+, SCFQ, SFQ, LLQ, and hybrid-LLQ.</li> </ul> <h3>L4S client</h3> <ul> <li>DualPI2 coupled AQM (RFC 9332) with ECT(1) classification (RFC 9331).</li> <li>Coupled classic / scalable congestion marking.</li> </ul> <h3>CAKE client</h3> <ul> <li>DSCP-to-tin mapping (besteffort, precedence, diffserv3, diffserv4, diffserv8) over per-tin FqCobalt with DRR++ scheduling.</li> <li>Host-pair isolation, ACK filtering, optional per-tin shaping, named link-layer-overhead and RTT presets, and per-tin diagnostics aligned with <code>tc -s qdisc show</code>.</li> </ul> <h3>Validation</h3> <ul> <li>17 test suites covering the three clients, RFC conformance vectors (RFC 2697 / 2698 / 2859 / 9331 / 9332), and cross-implementation reference fixtures.</li> <li>Reproduction tooling for the accompanying paper's figures (<code>scripts/reproduce-paper.sh</code>).</li> </ul> <h3>Requirements</h3> <ul> <li>A small set of ns-3 mainline patches (bundled in <code>patches/ns3/</code>), applied at the pinned revision. See <code>README.md</code> for the three install paths: into an existing ns-3 tree, a script-managed sibling clone, or Bake.</li> </ul>

Dependencies

Compulsory

  • cmake
  • ns-3.48

Stratum is a contributed ns-3 module: install it in the usual way (in the `contrib` directory), named `stratum`. It builds with a C++23 compiler against ns-3.48. Stratum carries a small set of ns-3 mainline patches that must be applied before building. ## From a source archive Use the blue **Download** button, or the **Release History** tab, to fetch a released version. Unpack it into `contrib/stratum` in an ns-3.48 tree, apply the bundled patches, then build: for p in contrib/stratum/patches/ns3/*.patch; do git apply "$p"; done ./ns3 configure --enable-tests --enable-examples ./ns3 build stratum python3 test.py -s 'stratum*' -v ## From git — into an existing ns-3 tree (recommended) git clone https://gitlab.com/nsnam/ns-3-dev.git ns-3 cd ns-3 git clone https://github.com/digitalities/stratum-ns3.git contrib/stratum git checkout "$(contrib/stratum/scripts/fetch-ns3.sh --print-pin)" for p in contrib/stratum/patches/ns3/*.patch; do git apply "$p"; done ./ns3 configure --enable-tests --enable-examples ./ns3 build stratum python3 test.py -s 'stratum*' -v ## From git — standalone (script-managed sibling clone) git clone https://github.com/digitalities/stratum-ns3.git cd stratum-ns3 ./scripts/fetch-ns3.sh # clones the pinned ns-3 as a sibling dir, applies patches, symlinks contrib/stratum `fetch-ns3.sh` clones the pinned ns-3 revision (query it with `--print-pin`), applies the patches in `patches/ns3/`, and creates the `contrib/stratum` symlink ns-3 expects. ## With Bake The repository ships a `bakeconf.xml` module definition. Add it to Bake's `contrib/` folder, then: ./bake.py configure -e ns-3.48 -e stratum ./bake.py download # apply the bundled mainline patches inside the downloaded ns-3 tree ( cd source/ns-3.48 && for p in contrib/stratum/patches/ns3/*.patch; do git apply "$p"; done ) ./bake.py build Applying the mainline patches as the first build step follows the ns-3 external-module guide (section 5.2) for patch-carrying modules. (Bake itself runs under Python 3.11–3.13 with the `distro` and `requests` packages installed.) ## Verifying the install The last two lines of every recipe do different jobs. `./ns3 build stratum` compiles the module; `python3 test.py -s 'stratum*' -v` runs Stratum's full suite set — DiffServ core (with the RFC 2697/2698 vectors), L4S, CAKE, the schedulers, and the reproduced reference scenarios. The `'stratum*'` glob (quote it so the shell does not expand it) matches every Stratum suite. ns-3 reports the tally per *suite* but labels each suite a "test" in its output, so a healthy run ends with: 19 of 19 tests passed (19 passed, 0 failed, 0 crashed) The left number is how many suites ran — it grows as coverage is added; the figure that matters is `0 failed` (and `0 crashed`), which is the signal the install is sound, not the build step alone. For a quicker single-suite smoke, use `-s stratum` instead. (Checking out a pinned ns-3 revision earlier leaves git in a "detached HEAD" state; that is expected and needs no action.) ## Next steps Run a bundled example to see a client end to end: ./ns3 run diffserv-example-1 Example recipes ship for DiffServ, L4S, and CAKE over both IPv4 and IPv6, and the handbook's command-line reference appendix lists every example's flags. The in-tree handbook (Part I — using Stratum; Part II — architecture; Part III — evidence) is where to continue.

Stratum is maintained by Sergio Andreozzi, the original DiffServ4NS author. Please report bugs and request features on the GitHub issue tracker: [https://github.com/digitalities/stratum-ns3/issues](https://github.com/digitalities/stratum-ns3/issues) The module is released under the GNU General Public License v2.0 (GPLv2), matching ns-3 mainline.

### Extending Stratum New AQMs and schedulers integrate as cells in a registry template — no fork, no edits to the composer core. A cell registers a factory and a name; CLI catalogues, plot palettes, documentation tables, and the smoke-registry tests then pick it up automatically. In-tree today: 13 AQM cells and 9 scheduler cells. ### Running the tests The module registers a suite per component area. ns-3's `test.py -s` matches a glob, so `-s 'stratum*'` runs every Stratum suite at once, or name one to run a single area: python3 test.py -s 'stratum*' -v # all Stratum suites python3 test.py -s stratum -v # DiffServ core (+ RFC 2697/2698 vectors) python3 test.py -s stratum-l4s -v # L4S DualPI2 (RFC 9331/9332) python3 test.py -s stratum-cake-q15 -v # CAKE composition Quote the glob so the shell does not expand it. `tcp-gso-egress` does not start with `stratum`, so to run the complete module set including it, loop over the discovered suites: for s in $(./ns3 run "test-runner --print-test-name-list" 2>/dev/null \ | grep -E '^(stratum|tcp-gso-egress)'); do python3 test.py -s "$s" done RFC conformance vectors run inside these suites: RFC 2697 / 2698 / 2859 metering in `stratum` and `stratum-meter-trace`; RFC 9331 / 9332 L4S identification and coupling in `stratum-l4s`. ### Contributing Development is spec-driven: a layered Intent → Structural → Quality spec suite gates every change. See `CONTRIBUTING.md` in the repository for the workflow, coding style, and the mainline-patch process. The architecture and the evidence base are documented in the in-tree handbook (Part II — architecture; Part III — evidence). Source code: [https://github.com/digitalities/stratum-ns3](https://github.com/digitalities/stratum-ns3)

This ns-3 extension is one or more contributed modules.

Version v2.0.1

Released June 25, 2026

Works with ns-3.48

Bake bakeconf.xml