Wire format, bit by bit¶
A hands-on tour of the actual bytes — like a protobuf encoding guide, but for
libtracer’s TLV. Every example is a real frame you can reproduce with
encode(). Read frame-codec for the API; this page is the bits.
The whole protocol is one shape, recursively: a Type-Length-Value. There are no field tags, no varints, no schema needed to walk the bytes — the header tells you everything, and a structured value is just more TLVs concatenated.
The header (4 bytes, or 6)¶
┌────────┬────────┬────────────────┐ ┌────────┬────────┬────────────────────────────────┐
│ type │ opt │ length (u16) │ or │ type │ opt │ length (u32) │
│ u8 │ u8 │ little-endian │ LL=1 │ u8 │ u8 │ little-endian │
└────────┴────────┴────────────────┘ └────────┴────────┴────────────────────────────────┘
byte 0 byte 1 bytes 2..3 byte 0 byte 1 bytes 2..5
type — one byte.
0x01VALUE,0x02NAME,0x06PATH,0x07POINT,0x09STATUS,0x0BSETTINGS,0x0CTIME,0x0FFWD … (0x80–0xFFis yours).opt — eight flag bits (below).
length — payload size, fixed-width little-endian:
u16normally,u32whenopt.LL=1. Fixed width means a parser jumpsheader + lengthto the next TLV with no scanning — the basis of the iterative (non-recursive) walk.
The opt byte, bit by bit¶
bit: 7 6 5 4 3 2 1 0
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ R │ PL │ TS │ CR │ LL │ CW │ TF │ R │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┘
│ │ │ │ │ │ │ │
reserved┘ │ │ │ │ │ │ └reserved (both MUST be 0;
(=0) │ │ │ │ │ │ non-zero ⇒ invalid)
│ │ │ │ │ │ └ TF timestamp form: 0=abs u64 ns, 1=rel i32
│ │ │ │ │ └ CW CRC width: 0=CRC-32C, 1=CRC-16-CCITT
│ │ │ │ └ LL length width: 0=u16, 1=u32
│ │ │ └ CR trailer carries a CRC
│ │ └ TS trailer carries a timestamp
│ └ PL payload is structured (children), not opaque bytes
└ (reserved)
So opt = 0x40 is 0b0100_0000 → PL=1 (structured). opt = 0x10 →
CR=1 (CRC trailer). You pay bytes only for the options you set; the default
opt = 0x00 is a bare opaque value with a 4-byte header.
Worked frames¶
1 · empty STATUS = OK (4 bytes)¶
The smallest frame — a write acknowledgement.
09 00 00 00
│ │ └──┴── length = 0x0000 = 0 (no payload)
│ └─────── opt = 0x00 (no flags)
└────────── type = 0x09 STATUS
An empty STATUS is “OK”. No body, no enum — absence is the signal.
2 · a VALUE carrying one byte (5 bytes)¶
A boolean true.
01 00 01 00 01
│ │ └──┴─ │ length = 0x0001 = 1
│ │ └─ payload[0] = 0x01 ← the value 'true'
│ └────────── opt = 0x00
└───────────── type = 0x01 VALUE
The payload bytes are opaque to the protocol — 0x01 means true only because
your schema says so. libtracer never interprets application data (just like JSON
doesn’t know your field is a temperature).
3 · a VALUE with a CRC trailer (13 bytes)¶
Same VALUE, payload AA BB CC DD EE, integrity-checked with CRC-32C.
01 10 05 00 AA BB CC DD EE B6 C9 12 23
│ │ └──┴─ └──────────────┘ └──────────┘
│ │ len=5 payload trailer: CRC-32C(payload) = 0x2312C9B6,
│ │ stored little-endian
│ └─ opt = 0x10 → CR=1 (trailer has a CRC)
└──── type = 0x01 VALUE
The CRC lives in the trailer, after the payload — not the header. That is what
lets a recorder or forwarder attach integrity at egress and strip it at ingress
without touching the payload bytes: at rest a value is header+payload; in
transit it grows a trailer; the payload is byte-identical through both.
4 · a structured PATH /sensor/temp (22 bytes)¶
opt.PL=1, so the payload is child TLVs concatenated — two NAMEs.
06 40 12 00 │ 02 00 06 00 73 65 6E 73 6F 72 │ 02 00 04 00 74 65 6D 70
└──┬───────┘ └────────────┬──────────────┘ └──────────┬──────────┘
│ NAME "sensor" (10 bytes) NAME "temp" (8 bytes)
│ 02=NAME 00=opt 0006=len s e n s o r
│
type=0x06 PATH · opt=0x40 (PL=1) · length=0x0012=18 (= 10 + 8 child bytes)
Walking it is the same loop as the outer frame: read a 4-byte header, jump
length, repeat. No special list type, no nesting markers — structure is
concatenation. And those 18 payload bytes are exactly the vertex-map key
(path): the address on the wire and the address in memory are the same
bytes.
5 · a FWD frame (the remote-operation envelope)¶
A remote write carried by the source-routed FWD (0x0F,
reference/05 §reserved range): the op code, the
explicit route to the target (dst), the accumulated way back (src), then the
payload TLV — FWD{ op=WRITE, dst=/b/temp, src=(empty), VALUE 0x2A }, 35 bytes:
0F 40 1F 00 ← FWD · opt=0x40 (PL=1) · length=0x001F=31
│ 01 00 01 00 01 ← VALUE op: 1 byte, WRITE=0x01
│ 06 40 0D 00 ← PATH dst (PL=1), 13 child bytes
│ 02 00 01 00 62 ← NAME "b" (the next-hop link)
│ 02 00 04 00 74 65 6D 70 ← NAME "temp" (the target on the peer)
│ 06 40 00 00 ← PATH src (PL=1), empty — grows per hop
│ 01 00 01 00 2A ← VALUE payload: the byte 0x2A
Every child is one of the shapes above — the frame is examples 2 and 4,
concatenated. A forwarding hop reads just the three leading headers by offset:
it strips NAME "b" from dst (shrinking it toward the target), prepends its own
name for the inbound link to src (the return route), and sends the rest of the
frame onward untouched — the payload bytes are never copied or re-encoded. When
dst no longer starts with a link name, the frame has arrived: the terminus decodes
it and applies the op. (0x0D is a reserved codepoint with no assigned mechanism.)
The same bytes, three ways¶
This is the payoff the byte layout buys: there is no separate “decode into a struct” step. The wire bytes, the in-memory value, and the graph node are one buffer.
flowchart LR
B["bytes:<br/>06 40 12 00 02 00 …"]:::b
B --> W["on the wire<br/>(a frame)"]
B --> M["in memory<br/>(a view_t → tlv_t, borrowed)"]
B --> G["in the graph<br/>(the vertex's value / key)"]
classDef b fill:#dbeafe,stroke:#1e40af;
Where the benefits live, in the bytes¶
You see in the bytes… |
…which buys |
|---|---|
4-byte header ( |
tiny per-message overhead; fits MCU MTUs |
fixed-width length |
jump to the next TLV with no varint scan → an iterative, bounded, recursion-free parser |
|
pay for timestamp/CRC/wide-length only when set; default frame is 4 bytes |
trailer-positioned CRC/TS |
attach/strip integrity & time without rewriting the payload (rest ⇄ transit) |
|
structure with no list type; a structured value is parsed in place as sub-spans |
payload = opaque bytes |
the protocol is a transparent carrier; your schema gives bytes meaning |
the key bytes = the PATH payload |
one address for wire and memory; dispatch is a byte compare |
Net: the bytes you receive are the bytes you keep — a decoded value is a set of
std::spans into the received buffer (views), so reading a field is a
pointer load and handing a value to N subscribers is N refcount bumps, not N copies.
That is the entire performance argument, visible in the layout.
API reference¶
Generated from core/include/libtracer/tlv.hpp by Doxygen.
-
struct opt_t¶
The 1-byte
optoptions bitfield of a TLV header.Bits, MSB→LSB: R | PL | TS | CR | LL | CW | TF | R. Bits 7 and 0 are reserved-MUST-be-zero (a set reserved bit ⇒
frame::invalid). See docs/reference/01-data-format.md §header + opt.Public Functions
-
inline constexpr std::uint8_t encode() const noexcept¶
Pack back into the raw
optbyte (reserved bits always zero).
-
inline constexpr opt_t without_trailer() const noexcept¶
The same opt with the trailer bits (TS/CR/CW/TF) cleared — only the structural bits (PL/LL) survive.
An ADR-0041 §4 trailer-sliced whole-TLV copy (op_resolve.cpp) applies this so the copy, whose bytes exclude the trailer by construction, stays self-consistent — the typed replacement for the raw
opt & 0x48mask that once encoded these bits.
Public Members
-
bool pl = false¶
bit 6: payload-is-structured (children, not opaque bytes).
-
bool ts = false¶
bit 5: trailer carries a timestamp.
-
bool cr = false¶
bit 4: trailer carries a CRC.
-
bool ll = false¶
bit 3: length width (false = u16, true = u32).
-
bool cw = false¶
bit 2: CRC width (false = CRC-32C, true = CRC-16-CCITT).
-
bool tf = false¶
bit 1: timestamp form (false = abs u64, true = rel i32).
Public Static Functions
-
static inline constexpr bool reserved_set(std::uint8_t b) noexcept¶
True iff a reserved bit is set in raw byte
b(⇒ the frame is invalid).
Public Static Attributes
-
static constexpr std::uint8_t kReservedMask = 0b1000'0001¶
The reserved-MUST-be-zero bit mask (bits 7 and 0).
-
inline constexpr std::uint8_t encode() const noexcept¶
-
enum class tr::wire::type_t : std::uint8_t¶
The core TLV type-code registry (0x01-0x10, docs/reference/05 §per-type layout).
0x05 is retired (was LIST, ADR-0003). 0x0E SPEC is the in-band vertex-creation spec (ADR-0017); 0x0F FWD and 0x10 FIELD are the remote-operation frames (RFC-0004 / ADR-0035, the v1 fast-track range 0x0F-0x1F). All are structured (opt.PL=1) and handled generically by the codec. Codes 0x11-0x13 are transport-plane route-handle control frames (RFC-0004 §E.1, ADR-0035 slice 4): they ride a full-TLV link (ws/UDP) ALONGSIDE FWD to compact an established,
delivery_compact-flagged flow into a per-link label. They are NOT part of the FWD frame and NOT cross-core conformance TLVs — a peer that ignores them simply keeps the full-route delivery path — but are self-describing (opt.PL=1) so the codec parses them generically.Values:
-
enumerator VALUE¶
Opaque scalar value.
-
enumerator NAME¶
UTF-8 name segment.
-
enumerator DESCRIPTION¶
Human-readable description.
-
enumerator SUBSCRIBER¶
Subscriber registration edge.
-
enumerator PATH¶
Structured path (a sequence of NAME children).
-
enumerator POINT¶
A point in a path/graph.
-
enumerator ERROR¶
Error report.
-
enumerator STATUS¶
Status report.
-
enumerator ACL¶
Access-control list.
-
enumerator SETTINGS¶
QoS settings.
-
enumerator TIME¶
Time.
-
enumerator ROUTER¶
Router-wrapped frame.
-
enumerator SPEC¶
In-band vertex-creation spec (structured; ADR-0017).
-
enumerator FWD¶
Remote-operation forward frame (RFC-0004 §B / ADR-0035).
-
enumerator FIELD¶
Control-plane
:fieldselector (RFC-0004 §C / ADR-0035).
-
enumerator ADVERTISE¶
Route-handle: VALUE label(u16) + PATH route — bind label→route, swapped per hop.
-
enumerator COMPACT¶
Route-handle: VALUE label(u16) + payload TLV — a label-compacted delivery.
-
enumerator HANDLE_NACK¶
Route-handle: VALUE label(u16) — stale/unknown label seen; prompts re-advertise.
-
enumerator VALUE¶
See: frame-codec · the normative data-format reference · the TLV catalog.