v0.21.0
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) andsafi_scan.rswere indexed, and the duplicatemrt_debug.rsentry was removed. Three new examples cover previously undocumented features:dissect_mrt.rs(renderingDissectionNodetrees with byte-offset gutters),ris_live_raw_full.rs(parse_ris_live_message_raw_fullon an embedded real message), andencode_as_path.rs(theAsPath/As4Pathvariant split,EncodingError::ValueTooLarge, and the AS_TRANS migration shape). - Updated
idna_adapterdependency from =1.2.0 to =1.2.2 (#328).
Breaking changes
-
DiagnosticIteratorevent redesign:DiagnosticEvent::Recordand::Validationmerge into a singleRecord { record, raw, warnings }variant — an emptywarningsvector means the record parsed clean, and every record now carries its originalRawMrtRecordbytes (previously onlyValidationandParseErrordid).ParseErrorgains apartial: 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::Aggregatorvariant split (#329): theis_as4: boolfield 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 withis_as4: truesilently emitted AS4_PATH (type 17) — an attribute RFC 6793 §4.2 reserves for 2-octet sessions. The flag is now structural, mirroringMpReachNlri/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(orpath.into()) and passAsnLength::Bits32toencode_to; segments encode as 4-octet automatically.As4Path/As4Aggregatorare 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 neweffective_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::ValueTooLargeinstead of silently writing the low 16 bits (e.g. 400644 → 7428). SubstituteAS_TRANS(23456) or useAs4Path/As4Aggregatorexplicitly. AGGREGATOR's AS-number width now follows the session'sasn_lenlike AS_PATH, instead of theAsnvalue's internal 2/4-octet flag.
Added
- Byte-level dissection (Wireshark-style field trees) (#332): new opt-in dissectors produce a
DissectionNodetree 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 yieldDissectedDiagnosticEvent— everyRecordevent gains the full dissection tree and its warnings becomeSpannedWarnings ({ span, warning }) anchored to the bytes they concern. Span correlation is post-hoc (span_record_warnings, also public): attribute-keyed warnings point at the matchingbgp.attr.{code}node (Nth occurrence for duplicates), NLRI warnings at their section, with fallbacks to enclosing sections.record_validation_warningsis 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 ofparseRisLiveMessageRawfor arbitrary BGP wire bytes. All three are exposed across Node.js, bundler, and web targets with TypeScript definitions (generatedDissectionNode/Span/SpannedWarningtypes 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 addsAttributes::as4_path()for raw access to the type-17 attribute.- Full-fidelity RIS Live raw parsing (#331, #297):
parse_ris_live_message_raw_fulldecodes a RIS Liveris_messageenvelope from its hexdata.rawBGP wire bytes and returnsRisLiveRawFull { meta, elems, attributes, validation_warnings }. Unlike the elem-only APIs,attributespreserves everything the elem conversion drops (originator ID, cluster list, AIGP, BGP Prefix-SID, raw-retained BGPSEC_PATH/ATTR_SET, ...) andvalidation_warningssurfaces RFC 7606 parse findings. The existingparse_ris_live_message_rawis unchanged; the full parser'selemsare identical to it by construction. - WASM RIS Live exports (#331): the
@bgpkit/parsernpm package now exposesparseRisLiveMessageJson(message)(RIS Live's JSON-projected UPDATE fields, noincludeRawneeded) andparseRisLiveMessageRaw(message)(requiressocketOptions.includeRaw = true; returns{ meta, elems, attributes, validationWarnings }with full attribute fidelity) across the Node.js, bundler, and web targets. Thewasmcargo feature now includesrislive. - Generated TypeScript types for the WASM attribute surface (#331): a new opt-in
ts-rscargo feature generatesAttribute,AttributeValue(fully typed common variants; opaqueRecord<string, unknown>for the long tail),BgpValidationWarning,Nlri,NextHopAddress, and the community types intosrc/wasm/js/generated/viaTS_RS_EXPORT_DIR=src/wasm/js/generated cargo test --features ts-rs,rislive. Generated files are committed.ExtendedCommunityin the shipped.d.tsis upgraded from an opaqueRecord<string, unknown>to the fully generated union, and the hand-writtenBgpElemdeclaration gains the previously missingunknown/deprecatedfields. - Type-drift CI (#331): a new
wasm-typesjob regenerates the ts-rs bindings and golden JSON fixtures (src/wasm/test/fixtures/, one perAttributeValuevariant plus elems, warnings, and an end-to-end RIS Live raw parse), fails ongit 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. BgpValidationWarningnow implementsserde::Serializeso 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_as4pathpreviously 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 exactlyroute_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
BgpElemback to attributes derivedis_as4from whether the origin AS number was 4-octet, which re-encoded such paths as type 17 on any session (#329).