Skip to content

v0.21.0

Choose a tag to compare

@github-actions github-actions released this 21 Aug 18:03
· 51 commits to main since this release
v0.21.0
169ed50

Examples restructure

  • Restructured examples/ and its README index: the README taxonomy was reorganized (Quickstart, Iteration Models, Filtering and Policy, Encoding and Export, Batch and Broker, Real-time Streams, Attributes and Metadata, Diagnostics/Dissection/Error Handling, RPKI, Standalone/WASM); bgp_open_role_pcap.rs (previously unlisted) and safi_scan.rs were indexed, and the duplicate mrt_debug.rs entry was removed. Three new examples cover previously undocumented features: dissect_mrt.rs (rendering DissectionNode trees with byte-offset gutters), ris_live_raw_full.rs (parse_ris_live_message_raw_full on an embedded real message), and encode_as_path.rs (the AsPath/As4Path variant split, EncodingError::ValueTooLarge, and the AS_TRANS migration shape).
  • Updated idna_adapter dependency from =1.2.0 to =1.2.2 (#328).

Breaking changes

  • DiagnosticIterator event redesign: DiagnosticEvent::Record and ::Validation merge into a single Record { record, raw, warnings } variant — an empty warnings vector means the record parsed clean, and every record now carries its original RawMrtRecord bytes (previously only Validation and ParseError did). ParseError gains a partial: Option<DissectionNode> field: a best-effort dissection tree showing how far the record's structure could be walked before the failure. Pattern matches on the old shapes must be updated.

  • AttributeValue::AsPath / AttributeValue::Aggregator variant split (#329): the is_as4: bool field conflated the wire attribute type (AS_PATH type 2 vs AS4_PATH type 17; AGGREGATOR type 7 vs AS4_AGGREGATOR type 18) with the AS-number segment width, so building an announcement for a 4-octet session with is_as4: true silently emitted AS4_PATH (type 17) — an attribute RFC 6793 §4.2 reserves for 2-octet sessions. The flag is now structural, mirroring MpReachNlri/MpUnreachNlri:

    Before After
    AttributeValue::AsPath { path, is_as4: false } AttributeValue::AsPath(path)
    AttributeValue::AsPath { path, is_as4: true } AttributeValue::As4Path(path)
    AttributeValue::Aggregator { asn, id, is_as4: false } AttributeValue::Aggregator { asn, id }
    AttributeValue::Aggregator { asn, id, is_as4: true } AttributeValue::As4Aggregator { asn, id }

    To build announcements for a 4-octet session, use AsPath (or path.into()) and pass AsnLength::Bits32 to encode_to; segments encode as 4-octet automatically. As4Path / As4Aggregator are for the RFC 6793 2-octet-session fallback and for reproducing captured migration attributes; their values always encode with 4-octet AS numbers. Serde note: the JSON shape of these variants changes from {"AsPath": {"path": ..., "is_as4": ...}} to {"AsPath": [...]} / {"As4Path": [...]}.

  • Attributes::as_path() semantics: now returns only the AS_PATH (type 2) attribute value. Previously it returned whichever path attribute appeared last — preferring AS4_PATH when both were present, without merging. Use the new effective_as_path() for the RFC 6793 §4.2.3 merged path.

  • Encoding errors instead of silent AS-number truncation (#329): encoding an AS number above 65535 into a 2-octet AS_PATH segment or AGGREGATOR now returns EncodingError::ValueTooLarge instead of silently writing the low 16 bits (e.g. 400644 → 7428). Substitute AS_TRANS (23456) or use As4Path / As4Aggregator explicitly. AGGREGATOR's AS-number width now follows the session's asn_len like AS_PATH, instead of the Asn value's internal 2/4-octet flag.

Added

  • Byte-level dissection (Wireshark-style field trees) (#332): new opt-in dissectors produce a DissectionNode tree in which every protocol field carries its byte range. dissect_bgp_message (src/parser/bgp/dissect.rs) covers the BGP header and all five message types — UPDATE fields walk into attribute internals (AS_PATH segments, communities of all three families, MP_REACH/MP_UNREACH structure, AIGP TLVs, aggregator components) and per-prefix NLRI; dissect_mrt_record / dissect_mrt_bytes (src/parser/mrt/dissect.rs) cover the MRT common header (including ET microsecond fields), the BGP4MP subheader (message and state-change layouts, old-Zebra compat detection), and delegate into the embedded BGP message so all layers share one offset coordinate space. Dissectors are separate best-effort passes — never on default parsing paths — and never fail: truncated input yields a partial tree, which is the basis for "edit a byte, see where parsing breaks" tooling.
  • DiagnosticIterator::with_dissection() (#332): upgrades the diagnostic iterator to yield DissectedDiagnosticEvent — every Record event gains the full dissection tree and its warnings become SpannedWarnings ({ span, warning }) anchored to the bytes they concern. Span correlation is post-hoc (span_record_warnings, also public): attribute-keyed warnings point at the matching bgp.attr.{code} node (Nth occurrence for duplicates), NLRI warnings at their section, with fallbacks to enclosing sections. record_validation_warnings is now public for custom investigation pipelines.
  • WASM dissection and full-fidelity exports (#332): dissectBgpMessage(data, fourByteAsn?) returns the field tree for one BGP message; dissectMrtRecord(data) returns { tree, bytesRead } for one MRT record; parseBgpUpdateFull(data) returns { elems, attributes, validationWarnings } — the sibling of parseRisLiveMessageRaw for arbitrary BGP wire bytes. All three are exposed across Node.js, bundler, and web targets with TypeScript definitions (generated DissectionNode/Span/SpannedWarning types via ts-rs, plus fixtures and type-drift checks).
  • Attributes::effective_as_path(): returns the RFC 6793 §4.2.3 effective AS path — AS_PATH and AS4_PATH merged when both are present, otherwise whichever exists — so callers no longer need to reimplement the merge logic. Also adds Attributes::as4_path() for raw access to the type-17 attribute.
  • Full-fidelity RIS Live raw parsing (#331, #297): parse_ris_live_message_raw_full decodes a RIS Live ris_message envelope from its hex data.raw BGP wire bytes and returns RisLiveRawFull { meta, elems, attributes, validation_warnings }. Unlike the elem-only APIs, attributes preserves everything the elem conversion drops (originator ID, cluster list, AIGP, BGP Prefix-SID, raw-retained BGPSEC_PATH/ATTR_SET, ...) and validation_warnings surfaces RFC 7606 parse findings. The existing parse_ris_live_message_raw is unchanged; the full parser's elems are identical to it by construction.
  • WASM RIS Live exports (#331): the @bgpkit/parser npm package now exposes parseRisLiveMessageJson(message) (RIS Live's JSON-projected UPDATE fields, no includeRaw needed) and parseRisLiveMessageRaw(message) (requires socketOptions.includeRaw = true; returns { meta, elems, attributes, validationWarnings } with full attribute fidelity) across the Node.js, bundler, and web targets. The wasm cargo feature now includes rislive.
  • Generated TypeScript types for the WASM attribute surface (#331): a new opt-in ts-rs cargo feature generates Attribute, AttributeValue (fully typed common variants; opaque Record<string, unknown> for the long tail), BgpValidationWarning, Nlri, NextHopAddress, and the community types into src/wasm/js/generated/ via TS_RS_EXPORT_DIR=src/wasm/js/generated cargo test --features ts-rs,rislive. Generated files are committed. ExtendedCommunity in the shipped .d.ts is upgraded from an opaque Record<string, unknown> to the fully generated union, and the hand-written BgpElem declaration gains the previously missing unknown/deprecated fields.
  • Type-drift CI (#331): a new wasm-types job regenerates the ts-rs bindings and golden JSON fixtures (src/wasm/test/fixtures/, one per AttributeValue variant plus elems, warnings, and an end-to-end RIS Live raw parse), fails on git diff, and type-checks the fixtures against the shipped .d.ts (src/wasm/test/type-check/). Any Rust model change that alters the WASM JSON output must regenerate both.
  • BgpValidationWarning now implements serde::Serialize so RFC 7606 warnings can cross the WASM/JSON boundary.

Fixed

  • RFC 6793 §4.2.3 AS_PATH/AS4_PATH merge now trims across segment boundaries (#330): AsPath::merge_aspath_as4path previously aligned the two paths segment-by-segment, producing wrong merges whenever segment boundaries did not line up (e.g. AS_PATH [1,2] [3,4] with AS4_PATH [9,10] merged to [9,10] [3,4] instead of [1,2] [9,10]). It now keeps exactly route_len(AS_PATH) - route_len(AS4_PATH) AS numbers from the leading part of the AS_PATH and prepends them to the whole AS4_PATH, per the RFC. This also corrects elem-level merged paths, which use the same function.
  • Elem-to-attributes conversion no longer mislabels 4-octet paths as AS4_PATH: converting a BgpElem back to attributes derived is_as4 from whether the origin AS number was 4-octet, which re-encoded such paths as type 17 on any session (#329).