Skip to content

NNSR Internal Compact Header Roadmap

Status: Planned

Last reviewed: 2026-06-22

Purpose

The target SD-WAN internal forwarding format is a 4-byte MPLS-style compact label named NNSR-C. It is an internal header: the label is carried inside the payload protected by the hop-by-hop WireGuard or QUIC underlay. A transit agent reads it only after local underlay authentication and decryption, then re-encrypts the packet to the next hop.

This document intentionally does not specify a public clear-label SD-WAN core. NexusNet trusts WireGuard/BoringTun and QUIC/TLS 1.3/REALITY for cryptographic protection instead of adding a custom end-to-end AEAD layer.

Diagram Name

The ASCII box drawings below are RFC-style packet layout diagrams, also called RFC-style bit diagrams or packet header bit-field diagrams. They show field boundaries by bit position and octet position.

Design Basis

The closest wire-format reference is MPLS label switching:

  • RFC 3032 defines a 4-octet label stack entry with a 20-bit label, 3-bit traffic class field, 1-bit bottom-of-stack flag, and 8-bit TTL.
  • The forwarding operation is label lookup, optional label replacement or pop, TTL update, and next-hop forwarding.
  • That behavior matches SD-WAN transit after underlay decapsulation: transit nodes should not re-run policy matching or own path computation.

Other RFC-shaped options are less suitable for the default NNSR header:

CandidateHeader CostFit
MPLS-style label shim, RFC 3032 model4 bytes per labelBest compact label-swap shape.
Geneve, RFC 89268 bytes plus optionsFlexible, but larger and more general than needed.
IPv6 SRH / SRv6, RFC 87548-byte base plus 16 bytes per segmentToo large for compact public SD-WAN paths.

MTU constraints push the design toward a small internal shim:

  • IPv6 Internet links must support at least a 1280-octet MTU.
  • UDP applications should avoid sending datagrams larger than the path MTU.
  • QUIC endpoints must handle at least 1200-byte UDP datagrams, so 1200 bytes is a useful conservative planning baseline for QUIC-backed paths.

4-Byte NNSR-C Header

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                 Label / SID                  | TC  |S|  TTL  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Fields:

FieldBitsMeaning
Label / SID20Node-local forwarding label in the active route generation.
TC3Traffic class. Initially zero; reserved for QoS, OAM, fallback class, or drop class.
S1Bottom-of-stack flag. Set to 1 for the initial single-label format.
TTL8Hop limit. Transit decrements it and drops at zero.

Encoding rules:

  • The 4-byte compact label is encoded in network byte order.
  • Label / SID occupies bits 31 through 12 of the 32-bit word.
  • TC occupies bits 11 through 9.
  • S occupies bit 8.
  • TTL occupies bits 7 through 0.

Octet encoding:

OctetBitsEncoding
07..0Label[19:12]
17..0Label[11:4]
27..4Label[3:0]
23..1TC[2:0]
20S
37..0TTL

The initial format uses one label only. Label stacking remains reserved for future service chaining or nested overlays, but the default SD-WAN path should stay single-label.

WG NNSR Packet Layout

WG NNSR means NNSR-C is the first bytes of the decrypted WireGuard tunnel payload. On the public wire, the compact label is encrypted and authenticated by the hop-by-hop WireGuard session.

Public underlay packet:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~              Outer IPv4 Header or Outer IPv6 Header          ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          UDP Source Port      |       UDP Destination Port    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          UDP Length           |       UDP Checksum            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                 WireGuard Message Type = Data                 |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                    WireGuard Receiver Index                   |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 +                         WireGuard Counter                     +
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~      AEAD ciphertext of: NNSR-C Label + Inner IPv4/IPv6       ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~                    WireGuard AEAD Tag (16 octets)             ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Payload visible to the agent after WireGuard decapsulation:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                 Label / SID                  | TC  |S|  TTL  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Ver|                                                           |
 +---+                                                           +
 |                                                               |
 ~                    Inner IPv4 or IPv6 Packet                  ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

WG NNSR decrypted payload offsets:

OffsetLengthField
04NNSR-C compact label.
4variableInner IPv4 or IPv6 packet. The first nibble is 4 or 6.

WG NNSR overhead before the inner IP packet:

LayerBytes
Outer IPv4 header20
Outer IPv6 header40
UDP header8
WireGuard data header16
WireGuard AEAD tag16
NNSR-C label4

This gives 64 bytes before inner IP on IPv4 underlay and 84 bytes before inner IP on IPv6 underlay. Link-layer overhead is outside this count.

QUIC Tunnel NNSR Packet Layout

QUIC Tunnel NNSR means NNSR-C is inside a QUIC DATAGRAM after QUIC packet protection has authenticated and decrypted the packet. The compact label is not visible to an external observer on the public wire.

Public underlay packet:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~              Outer IPv4 Header or Outer IPv6 Header          ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          UDP Source Port      |       UDP Destination Port    |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |          UDP Length           |       UDP Checksum            |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~             QUIC Header (long or short, variable)             ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~    QUIC packet-protected payload, including DATAGRAM frame    ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

QUIC DATAGRAM frame after QUIC packet protection is removed:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |        DATAGRAM Frame Type (QUIC varint, usually 1B)          |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |        Optional DATAGRAM Length (QUIC varint, if present)     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                                                               |
 ~                    DATAGRAM Application Data                  ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Preferred Nexus QUIC Tunnel NNSR application data after QUIC decapsulation:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                 Label / SID                  | TC  |S|  TTL  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Ver|                                                           |
 +---+                                                           +
 |                                                               |
 ~                    Inner IPv4 or IPv6 Packet                  ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Preferred QUIC Tunnel NNSR application-data offsets:

OffsetLengthField
04NNSR-C compact label.
4variableInner IPv4 or IPv6 packet. The first nibble is 4 or 6.

HTTP/3 DATAGRAM compatible application data can keep an existing context prefix:

text
  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |        Quarter Stream ID / Context ID (QUIC varint, 4B)       |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |                 Label / SID                  | TC  |S|  TTL  |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 |Ver|                                                           |
 +---+                                                           +
 |                                                               |
 ~                    Inner IPv4 or IPv6 Packet                  ~
 |                                                               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

To keep NNSR-C 32-bit aligned in this compatible mode, SD-WAN QUIC contexts should use the QUIC varint range that encodes in 4 bytes:

text
16384 <= context_id <= 1073741823

HTTP/3-compatible offsets:

OffsetLengthField
04Quarter Stream ID / Context ID, encoded as a 4-byte QUIC varint.
44NNSR-C compact label.
8variableInner IPv4 or IPv6 packet. The first nibble is 4 or 6.

Forwarding Semantics

Transit lookup key:

text
(route_generation, local_label)

Transit lookup value:

text
action: swap | pop | drop
next_label
next_node_short_id
underlay_profile_id
mtu
counter ids
egress_action_id, only for pop entries

Transit behavior:

text
decrypt/authenticate local WG or QUIC underlay
parse 4-byte NNSR-C label
if TTL <= 1: drop and count ttl_expired
lookup (generation, label)
if miss: drop and count missing_forward_entry
if action = swap:
  replace label with next_label
  decrement TTL
  send via next hop WG or QUIC underlay
if action = pop:
  strip 4-byte header
  execute egress action

Ingress behavior:

text
match packet against SD-WAN policy
select active path and first local label from runtime table
prepend NNSR-C label with configured TTL
send via first hop WG or QUIC underlay

Egress behavior:

text
decrypt/authenticate local WG or QUIC underlay
pop label
execute NAT, remote_tun, local_route, service_upstream, or drop

Why Remove 18 Bytes

The existing 18-byte header carries fields that are redundant on the fast path:

Current FieldCompact Replacement
path_idLabel table entry metadata.
hop_indexEncoded by local label progression.
path_lenNot needed by transit; TTL prevents loops.
ip_versionInner packet first nibble after pop.
flow_hashUnderlay session, UDP source port, QUIC connection routing, or table metadata.
payload_lenDatagram length from QUIC DATAGRAM, WG packet, or packet buffer length.

The 14-byte saving is not the whole MTU story, but it compounds with QUIC, WireGuard, NAT, and conservative MSS planning. Keeping both formats would also split runtime negotiation, tests, UI naming, and operational diagnosis, so the old codec should be deleted instead of retained as debug mode.

Public Internet Encapsulation

The public wire format is never:

text
Outer IP / UDP
NNSR-C clear label
Inner IPv4/IPv6 packet

The production public wire format is:

text
Outer IP / UDP
WG or QUIC protected packet
  encrypted/authenticated payload:
    NNSR-C compact label
    Inner IPv4/IPv6 packet

This means:

  • Public observers cannot read NNSR labels.
  • A transit node can read NNSR only after decrypting its local underlay session.
  • The next hop can decrypt because the previous hop re-encrypts the NNSR payload into the next hop's WG or QUIC session.
  • Encryption cost is hop-by-hop and scales with the number of underlay links in the path.

eBPF And Userspace Fit

NNSR-C is small enough for fast userspace processing. It is not a commitment to public pre-decrypt tc/XDP forwarding.

Allowed optimization paths:

  • Userspace parses, decrements TTL, swaps the 20-bit label, and forwards through the selected WG/QUIC adapter.
  • QUIC and WG workers can batch decrypt, lookup, and enqueue next-hop sends.
  • A future post-decap helper can optimize label lookup after underlay protection is removed.
  • A clear-label tc/eBPF mode may exist only as a non-default controlled profile.

Not a near-term goal:

  • NIC-level eBPF reading NNSR-C directly from public packets.
  • Public clear-label label swap as the normal SD-WAN mode.

Implementation Plan

  1. Add a versioned NNSR-C codec.
  2. Extend backend runtime generation with per-hop local labels and action type: swap, pop, or drop.
  3. Add userspace compact transit tests for ingress, swap, pop, TTL expiry, missing label, and route generation replacement.
  4. Add runtime feature negotiation for nnsr_compact_label_v1.
  5. Wire NNSR-C through QUIC REALITY and BoringTun WG adapters.
  6. Migrate frontend path inspector to display both logical path and compact label entries.
  7. Switch all new route generations to compact labels.
  8. Add regression tests that new runtime config emits only NNSR-C over protected underlay sessions.

Open Decisions

DecisionCurrent Direction
Label scopeNode-local per route generation.
Underlay securityHop-by-hop WG or QUIC/TLS 1.3; no custom NNSR AEAD.
Stack supportReserve S; single-label default.
TC semanticsInitially zero; reserve for OAM/fallback/QoS classes.
AuthenticationUnderlay authentication plus generation-scoped labels.
Replay handlingUnderlay-specific; compact label does not solve replay by itself.
FragmentationAvoid fragmentation through MTU/MSS planning and PLPMTUD-style probing.

References

  • RFC 3032: MPLS Label Stack Encoding.
  • RFC 2784: Generic Routing Encapsulation.
  • RFC 7348: Virtual eXtensible Local Area Network.
  • RFC 8754: IPv6 Segment Routing Header.
  • RFC 8926: Geneve.
  • RFC 8085: UDP Usage Guidelines.
  • RFC 8200: IPv6 Specification.
  • RFC 9000: QUIC.

NexusNet documentation