DNX Proposals
Changes argued before they are built
A DNXP is a proposed change to the protocol, written up in enough detail to be disagreed with. The point is that the argument happens before the code, and stays readable afterwards.
The process
Two document types, deliberately not three:
- Journal — decisions already made, and the reasoning or the bug that forced them. This is the historical record.
- DNXP — a change that has not been decided. It states the problem, the proposed design, what the proposal costs, and what remains unresolved.
A proposal that is accepted and built graduates into the specification, with a journal entry recording why. A proposal that is rejected stays here, marked as such, because the reasoning is often more useful than the outcome.
| Status | Meaning |
|---|---|
| Draft | Under discussion. May change substantially or be withdrawn. |
| Accepted | Agreed in principle, not yet implemented. |
| Implemented | Built and merged into the specification. |
| Rejected | Declined. The reasoning is retained. |
| Superseded | Replaced by a later proposal. |
Index
| Number | Title | Status |
|---|---|---|
| DNXP-0001 | Variable-length namespace paths | Implemented not yet on the live network |
DNXP-0001 · Variable-length namespace paths
Status: Implemented · Replaces: the fixed four-field destination address in the current implementation.
The library exists and is tested, and writing it settled two of the questions this proposal originally left open (below). It is not yet carrying traffic: the live demonstration still uses the fixed address, because replacing a working demonstration with an untested one is not an improvement. Migration follows the staged plan at the end of this document.
Summary. Replace the fixed 256-bit destination — four 64-bit fields for top level, domain, subdomain and host — with a variable-length ordered path of numeric namespace identifiers resolved by the registry. Hierarchy depth becomes unbounded, and no text ever appears on the wire.
Motivation
The current address assumes exactly four levels of hierarchy. That assumption survives contact with small examples and fails immediately on real organisational structure:
printer.office.company fits — three levels
api.production.us-east.customer.company does not fit — five
vpn.engineering.floor3.buildingA.company does not fit — five
A protocol in which adding an organisational level requires changing the packet format has a structural problem, not a configuration problem. Four was chosen because it made every forwarding decision a fixed-offset comparison — an implementation convenience promoted into an architectural limit.
There is a second motivation. The current scheme derives the lower two fields by truncating a hash of the label to 64 bits. That is convenient and it introduces a collision vector: distinct labels can map to the same field value, and a deliberate collision is roughly 232 work — hours of commodity hardware. Registry-assigned identifiers remove that class of problem entirely, because identifiers are allocated rather than computed.
Design
A destination becomes an ordered sequence of namespace identifiers, most significant first, with an explicit count. The registry translates between human names and identifiers; routers never see text.
human host1.dnx.dnxroute.com
│
registry ├─ com → 0x0000_1A2B
├─ dnxroute → 0x0000_4C19
├─ dnx → 0x0000_0007
└─ host1 → 0x0000_0031
│
wire [ count = 4 ][ 1A2B ][ 4C19 ][ 0007 ][ 0031 ]
Forwarding is unchanged in character: a router reads the identifier at the level it owns, matches it against its table, and forwards. It still never reads the whole path, and still never reads the payload.
Should identifiers be globally unique?
This is the substantive design decision in the proposal, and the recommendation is parent-scoped: an identifier need only be unique among its siblings, not across the whole namespace.
The argument is that forwarding is inherently top-down. A router responsible for level k only ever sees packets whose levels 0 through k−1 have already matched — so the parent context is guaranteed by the time the identifier is interpreted. Ambiguity cannot arise.
| Parent-scoped | Globally unique | |
|---|---|---|
| Allocation | Purely local — each namespace assigns its own | Requires global coordination or hashing |
| Identifier size | Small and dense | Large, or sparse and collision-prone |
| Governance | No central allocator needed | A central allocator, or back to hashing |
| Matching a deep level alone | Not possible without context | Possible |
The last row is the only real cost, and hierarchical forwarding never needs that capability. Both DNS delegation and MPLS label assignment work this way, which is reassuring company.
Parent-scoping also dissolves a governance objection raised against DNX repeatedly: that one organisation would end up controlling all naming. If identifiers are allocated locally by each namespace operator, no global allocator exists to be captured.
Wire format
Proposed encoding: a one-byte level count followed by that many 32-bit identifiers.
+---------+-----------+-----------+-----+-------------+
| count | NID[0] | NID[1] | ... | NID[count-1]|
| 1 byte | 4 bytes | 4 bytes | | 4 bytes |
+---------+-----------+-----------+-----+-------------+
Thirty-two bits per level allows roughly four billion children under any single parent, which is comfortably beyond the largest existing zones. Sixteen bits was considered and rejected: some top-level zones already contain more than sixty-five thousand children.
A pleasant side effect is that the common case gets smaller, not larger:
| Depth | Current fixed address | Proposed |
|---|---|---|
| 3 levels | 32 bytes | 13 bytes |
| 4 levels | 32 bytes | 17 bytes |
| 8 levels | impossible | 33 bytes |
| 20 levels | impossible | 81 bytes |
What this costs
The current design supports a specific claim: that a router masks the address at a fixed offset and compares integers — precisely the operation existing routing silicon performs. Variable length weakens that. A router must read the count, then index to the level it owns. Still integer comparison, no longer constant-offset.
The counter-argument is that this exact pattern already runs at line rate in production. MPLS forwards variable-depth label stacks in hardware, worldwide, and has for two decades — each hop reading only the top label. "Variable-depth stack of small identifiers, each hop reading one" describes MPLS and this proposal equally well.
Adopting this proposal therefore obliges the specification to answer a question it currently avoids: how is DNX different from MPLS? The honest answer is that MPLS labels are locally significant, signalled per path, and carry no identity, whereas these identifiers are namespace-derived, meaningful within their parent everywhere, and bound to keys. That difference should be argued explicitly rather than assumed.
Open questions
- Identifier reuse. Answered Generation counters turned out to be unnecessary. Allocation is monotonic and an identifier is never reissued, so a packet in flight or a stale forwarding entry can never be delivered to something that inherited its number. Four billion allocations beneath a single parent is not a limit anyone will reach, and never reusing is simpler than versioning what was reused.
- Diagnosis. Answered The implementation provides reverse resolution: a path can be translated back into the name it was addressed to, and an identifier that was never allocated is reported as unknown rather than guessed at. Without this a misdelivered packet is an unreadable row of integers, which is exactly the situation in which someone needs to read it.
- Depth limit. Answered Capped at sixteen levels. The count field could express 255; nothing legitimate approaches sixteen, and an unbounded walk is an invitation. Encoding or decoding a deeper path is refused.
- Table population. Routers must learn which identifiers map to which next hop. Today those tables are configured by hand. This proposal does not address how they would be distributed, which remains the largest unbuilt piece of the routing design.
Migration
This is a breaking change to the routed frame format. The migration path follows the pattern already used elsewhere in DNX, where formats are distinguished by their first byte and coexist during transition:
- Done Implement the new path format alongside the existing fixed address, under a distinct frame marker. Routers now decode either, and both share one forwarding walk rather than there being a second copy of the routing logic. Demonstrated through a single topology: a fixed address delivered to one host and a namespace path to another, both crossing the inter-node hop.
- Run both on the live network, with routers accepting either. Built, not yet deployed.
- Move the public demonstration to the new format once it has been exercised.
- Remove the fixed-address path.
The current live routing demonstration will remain on the fixed four-field format until the replacement has been tested, on the principle that a working demonstration should not be broken to make room for an untested one.