Skip to content

feat: packet highlight#146

Draft
YuanYuYuan wants to merge 15 commits into
eclipse-zenoh:mainfrom
ZettaScaleLabs:feat/packet-highlight
Draft

feat: packet highlight#146
YuanYuYuan wants to merge 15 commits into
eclipse-zenoh:mainfrom
ZettaScaleLabs:feat/packet-highlight

Conversation

@YuanYuYuan
Copy link
Copy Markdown
Contributor

No description provided.

@YuanYuYuan YuanYuYuan marked this pull request as draft April 20, 2026 13:42
Each field in the Wireshark protocol tree now highlights exactly
the bytes that encode it in the hex pane, rather than the entire
parent message.

Key changes:
- span.rs: SpanCursor (Reader + BacktrackableReader) wraps a byte
  slice and tracks read position; ByteSpan, SpanMap, RecordSpans
- zenoh_spans.rs: hand-written RecordSpans for each TransportMessage
  variant, following the wire format in zenoh-codec order
- tree.rs: TreeArgs gains spans: Option<&SpanMap>; make_subtree
  and field_span() look up per-field byte ranges from the map
- macros.rs: impl_for_struct! consults args.field_span() before
  proto_tree_add_string instead of using the parent message range
- lib.rs: after rbatch.decode(), build SpanMap via record_spans
  on the raw TVB bytes (non-compression path), shift spans to
  absolute TVB offsets, pass into TreeArgs per message

Fields covered: version, whatami, zid, resolution, batch_size,
lease, initial_sn, cookie, sn. Header-embedded fields (reliability,
session, more) fall back to the parent message range.
iext encoding is in bits 5-6 (ENC_MASK = 0x60), not bits 0-1.
ENC_UNIT has no body, ENC_Z64 has a VLE u64, ENC_ZBUF has a
u32-bounded length-prefixed buffer. The previous skip_extensions
assumed all extensions had a VLE body length, causing InitSyn/InitAck
span recording to fail and fall back to parent-message range for all fields.
- WireExpr sub-field spans: scope (VLE) and suffix (VLE-len + string)
- NetworkMessage spans: Push wire_expr, Declare body id and wire_expr,
  Request/Response wire_expr and id
- Extension spans: all network message extensions (ext_qos, ext_tstamp,
  ext_nodeid) and transport extensions (ext_qos, ext_auth, ext_mlink,
  ext_qos_link)
- Disambiguate extensions with same ID but different encoding via
  (enc_bits | id) matching

Verified with tshark -T pdml: wire_expr shows correct byte ranges
(27B for 25-char key, 14B/5B for declare sub-fields), extension
ext_qos in InitAck shows 1B (unit extension).
Register dissector for UDP port 7446. Detect scouting messages by
checking if the first byte mid is SCOUT(0x01) or HELLO(0x02), then
decode with Zenoh080::read() into ScoutingMessage.

Add impl_for_struct!/impl_for_enum! for Scout, HelloProto,
ScoutingBody, ScoutingMessage types. Register all scouting HF/ST
fields via ZenohProtocol::generate_hf_map/generate_subtree_names.
- tree.rs: field_span fallback changed from (start, full_length) to
  (start, 0) so unrecorded fields show no highlight instead of
  highlighting the entire message (Bug 3 fix)

- span.rs: add skip_remaining() helper for consuming payload bytes

- zenoh_spans.rs: add span recording for previously-missing fields:
  * Frame.ext_qos extension
  * Close.reason byte
  * Put.encoding, Put.timestamp, Put.payload (via record_put_body_spans)

- zenoh_impl.rs: registration tests (catch Bugs 1/2 from zids-and-trees),
  integration test dissector.rs verifies Bug 3 (nested field sizes) passes

- Cargo.toml: crate-type includes "rlib" to enable cargo test
When a Frame payload contains multiple Declare sub-messages, all messages
share the same span-map prefix key (tree uses fixed field names, not
indices). Recording all messages and letting later ones overwrite caused
the first Declare's fields to highlight the second Declare's bytes.

Fix: record spans only for the first NetworkMessage in the payload loop.
The first message highlights correctly; subsequent messages show size=0
(no highlight) rather than pointing to wrong bytes.

Integration test added: two-Declare Frame asserts that DeclareKeyExpr.id
has size=1 at the correct position, catching the overwrite regression.
…message frames

Root cause: the #[dissect(vec)] renderer passed the same TreeArgs (with
one shared span map) to all NetworkMessages in a Frame payload. Spans
were recorded with the same keys regardless of which message they
belonged to, causing the last message's spans to overwrite earlier ones.

Fix:
- zenoh_spans.rs: record indexed keys per message: "{payload}[{i}].…"
- macros.rs: #[dissect(vec)] now builds a per-item local_spans by
  filtering and remapping "{vec}[{i}].…" → "{vec}.…" for each item i
- tree.rs: add local_spans: Option<SpanMap> to TreeArgs; field_span
  checks it before shared spans; make_subtree propagates it so nested
  field lookups in subtrees also use the remapped keys

All NetworkMessages in a Frame now highlight their own correct bytes.
The HACK in impl_for_struct! that resets tree args for recursive descent
was resetting local_spans to None. This broke span lookup for any field
reached via #[dissect(expand)], including all NetworkBody variants
(Push, Request, Declare, etc.) which are reached through
NetworkMessage.expand(body: NetworkBody).

Fix: preserve local_spans via .clone() instead of setting it to None.
- Transport prefix: body_prefix -> tp (zenoh.body.* -> zenoh.transport.*)
- Frame payload: payload_prefix now zenoh.transport.frame.network.*
- Network dispatcher: remove stale .body infix from sub-function calls
- Declare variants: remove .body. from declare key paths
- Scouting: remove spurious .body. prefix (zenoh.body.scout -> zenoh.scout)
- Fragment: record reliability from header byte alongside more flag
- Undeclare: add span recording for U_KEYEXPR/U_SUBSCRIBER/U_QUERYABLE/U_TOKEN
- Put payload: skip VLE length prefix, record only the payload bytes
- Put prefix: pass "{prefix}.push" not "{prefix}.push.payload" to record_put_body_spans

Unit tests updated to match new key paths.
Add tshark-based integration tests covering all message types:
- KeepAlive, Close: basic decode
- Fragment: reliability + sn fields
- Join: version, whatami, zid, lease
- Push/Put: wire_expr, encoding, payload
- Declare{KeyExpr,Subscriber,Queryable,Token}: id + wire_expr
- Undeclare{KeyExpr,Subscriber}: id field
- DeclareFinal: presence check
- Request: id + wire_expr
- Response/ResponseFinal: rid + wire_expr
- Scout/Hello (UDP scouting): version, what/whatami, zid
- Multi-message frame: correct per-item byte offsets
- sample-data.pcap: all encoded fields have size>0 (no unclaimed fields)

Also add: ethernet_ipv4_udp_packet helper, UDP pcap writer,
tshark -d udp.port==7446,zenoh dissector override, unclaimed_fields
filter extended to exclude subtree nodes and ZID/batch overlay fields.
@YuanYuYuan YuanYuYuan force-pushed the feat/packet-highlight branch from e1f223b to 50d36a6 Compare April 20, 2026 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant