The TLV header and the opt byte (L2/L3 codec)¶
Every TLV on the wire opens with four bytes: a type code, the one-byte opt bitfield, and a
little-endian u16 length — widening to a u32, six bytes in all, once the body exceeds
0xFFFF (reference 01 §header + opt). There is no varint
and no checksum in the header; integrity is a trailer, and it is optional.
This is the first thing to read before any other page in this domain.
What to notice¶
optis a bitfield with two reserved bits.opt_t::encode/opt_t::decoderound-trip the six meaningful bits exactly, and bits 7 and 0 are reserved-MUST-be-zero.reserved_setanswers that question about a raw byte, before anything has been parsed — a set reserved bit makes the frame invalid (wire-format bits).The length width is
emit_tlv’s decision, not the caller’s. The example passesopt_t{.ll = false}with a 64 KiB body and gets a six-byte header withLLset anyway. Before #924 a programmatically built tree could serialize a length truncated tosize & 0xFFFF; the widen rule now lives with whoever writes the header.emit_headeris one level below, and does not decide. It writes the widthopt.llnames, verbatim. A byte-builder that reaches for it owns the width decision itself — which is safe when a grammar bound already caps the length, and a bug otherwise.Nothing here is conditional. The target builds and runs identically under every CI leg, net plane on or off.
Source¶
1/*
2 * SPDX-License-Identifier: Apache-2.0
3 * SPDX-FileCopyrightText: Copyright 2026 avatarsd LLC
4 */
5
6/**
7 * @file
8 * @brief ONE CONCEPT — the TLV header: `<type> <opt> <length>`, and the `opt` byte.
9 *
10 * Every TLV on the wire starts with four bytes: a type code, the one-byte `opt` bitfield,
11 * and a little-endian `u16` length — widening to a `u32` (six bytes in all) when the body
12 * exceeds `0xFFFF` (`docs/reference/01-data-format.md` §header + opt). There is no varint
13 * and no CRC in the header. Two facts a first-contact reader needs are checked here: the
14 * `opt` byte round-trips through `opt_t::decode`/`encode` exactly, with bits 7 and 0
15 * reserved-MUST-be-zero; and the length width is `emit_tlv`'s decision, not the caller's —
16 * an oversize body widens the header whatever `opt.ll` was passed as (#924).
17 *
18 * Runs under ctest as `example_wire_tlv_header`; returns non-zero on any failed check.
19 */
20
21#include <cstddef>
22#include <cstdint>
23#include <cstdio>
24#include <vector>
25
26#include "libtracer/tlv_emit.hpp"
27#include "libtracer/tracer.hpp"
28
29namespace {
30
31using tr::wire::opt_t;
32using tr::wire::type_t;
33
34/** @brief Report expectation @p what and record a failure on @p ok. */
35void check(bool& ok, bool cond, const char* what) {
36 std::printf(" [%s] %s\n", cond ? "ok" : "FAIL", what);
37 ok = ok && cond;
38}
39
40/** @brief The raw `opt` byte of the TLV that starts at the front of @p frame. */
41std::uint8_t opt_byte(const std::vector<std::byte>& frame) {
42 return static_cast<std::uint8_t>(frame[1]);
43}
44
45} // namespace
46
47int main() {
48 bool ok = true;
49
50 // The opt byte is a bitfield, not an enum: pack it, unpack it, get the same bits back.
51 const opt_t set{.pl = true, .ts = false, .cr = true, .ll = false, .cw = false, .tf = false};
52 std::printf("opt{pl,cr} encodes to 0x%02X\n", set.encode());
53 check(ok, opt_t::decode(set.encode()) == set, "opt_t encode/decode round-trips exactly");
54 check(ok, !opt_t::reserved_set(set.encode()), "a well-formed opt leaves bits 7 and 0 clear");
55 check(ok, opt_t::reserved_set(0x81), "a set reserved bit is detectable before any parse");
56
57 // A small body: the 4-byte header, length as u16 LE, LL clear.
58 const std::vector<std::byte> small(4, std::byte{0xAB});
59 std::vector<std::byte> narrow;
60 tr::wire::emit_tlv(narrow, type_t::VALUE, opt_t{}, small);
61 std::printf("4-byte body -> %zu bytes on the wire, opt = 0x%02X\n", narrow.size(),
62 opt_byte(narrow));
63 check(ok, narrow.size() == 4 + small.size(), "a small TLV carries a 4-byte header");
64 check(ok, (opt_byte(narrow) & 0x08) == 0, "the LL bit stays clear for a u16 length");
65
66 // An oversize body widens the header to six bytes and sets LL — even though the opt
67 // passed in said otherwise. emit_tlv owns the width decision; the caller does not.
68 const std::vector<std::byte> big(0x1'0000, std::byte{0xCD});
69 std::vector<std::byte> wide;
70 tr::wire::emit_tlv(wide, type_t::VALUE, opt_t{.ll = false}, big);
71 std::printf("65536-byte body -> %zu bytes on the wire, opt = 0x%02X\n", wide.size(),
72 opt_byte(wide));
73 check(ok, wide.size() == 6 + big.size(), "an oversize body widens the header to 6 bytes");
74 check(ok, (opt_byte(wide) & 0x08) != 0, "and emit_tlv sets LL itself, ignoring the opt given");
75 return ok ? 0 : 1;
76}
See also: frame codec · wire-format bits · data-format reference.