The whole job is one new file plus one registration line. Budget: well under an hour (PRD §8 — the template exists to keep it that way).
Not sure what to add yet? Run pktflow unknown -r capture.pcap against real traffic
first — it groups everything no plugin claimed or no heuristic was confident about, ranked
with near-miss scores and real sample bytes. pktflow unknown '#n' --scaffold NAME does step
1 below for you, pre-filled with the group's route — see
docs/unknown-diagnostics.md.
-
Copy the template.
cp crates/pktflow-plugins/src/template.rs crates/pktflow-plugins/src/<your_protocol>.rs, renameTemplateand thename()string (lowercase snake_case, unique). -
Fill in your header. Replace the PKTT fields with your protocol's: field-name constants at the top,
parse()reading throughByteReaderonly (no indexing), fields gated onctx.depth()— flow-key fields at>= Keys, structure at>= Structural, everything else atFull. Return the most explicitHintyour header allows; decline withParseErrorwhen the bytes aren't yours. -
Declare how you're reached.
claims()with your route ids (EtherType, IP protocol, ports, or aCustomspace). Add an honestprobe()+has_probe()only if your header is recognizably structured; most protocols should skip it. -
Declare your streams.
stream_identity()with the endpointKeyFields and any rollups. ReturnNoneif your layer qualifies its parent instead of forming conversations (see vlan).Endpoint-less protocols that want rollups (the app-stream pattern): if your protocol's conversation is the transport stream (DNS, DHCP, NTP), declare a key of one shared field —
KeyField { a: "app", b: None }— on a constant the plugin always emits (app = Str("dns")). You get exactly one child stream per transport stream: a clean home for rollups without inventing endpoint semantics. See dns.rs.Fan-out-prone protocols (D16): if one of your key pairs is an ephemeral dimension — many short flows differing only in that pair's value on one side, like TCP/UDP's port pair — also override
condense()to name it. Beyond a threshold, same-anchor flows fold into one condensed node instead of drowning the view. Requires anEndpointSortidentity whosekeycontains the pair; see tcp.rs. -
Register it. Add one
.plugin(your_protocol::YourProtocol)line todefault_engine()incrates/pktflow-plugins/src/lib.rs. Duplicate names or route claims fail the build with an error naming both parties. -
Test it. Keep the in-file tests (fixture parse from real capture bytes with a source comment, truncation, hint). Then add a
ConformanceCasefor your plugin intests/conformance.rs— the 09.1 kit mechanically checks truncation safety, depth monotonicity, flow-key coherence/involution, header honesty, probe honesty, and lifecycle totality for you.
Run just ci. If the registry build or the kit rejects your plugin, the
message names the rule it violated.