Skip to content

v0.22.0

Latest

Choose a tag to compare

@github-actions github-actions released this 10 Sep 15:37
· 25 commits to main since this release
v0.22.0
94c1832

Breaking changes

  • MSRV raised to Rust 1.88 (#338): rust-version in Cargo.toml is now 1.88.0. The idna_adapter dev-dependency pin is removed as it is no longer needed.
  • Announcement::next_hop is now the verbatim RIS Live string (#339) (String, was IpAddr): the field can carry a comma-joined RFC 2545 global + link-local pair (see Fixed below), so like prefixes it now keeps the wire value — parse it with NextHopAddress's new FromStr. Related edges: NextHopAddress's Display renders a pair comma-joined (round-tripping with FromStr), and BgpModelsError gains a NextHopParsingError variant.
  • BgpModelsError and ParserRisliveError are now #[non_exhaustive] (#340): both enums gain a variant in this cycle (NextHopParsingError, UnparsedMessageBody), and future additions will no longer break exhaustive matches downstream.
  • parse_ris_live_message now errors on a body it could not deserialize (#340): a frame that declares a message type this crate decodes but whose body fails to parse returns ParserRisliveError::UnparsedMessageBody with the underlying reason, where it previously returned Ok(vec![]). The flattened RisMessage::msg Option hid such failures, which is how the comma-joined next-hop bug (see Fixed below) dropped a frame's routes without a trace. Frames whose message type this crate does not decode still return no elems.

Dependencies

  • Updated oneio dependency from 0.25 to 0.26 (#338): clears the suppaftp advisory (RUSTSEC-2026-0271) that cargo audit reported via oneio 0.25's lockfile entry.
  • Updated ts-rs dependency from 11 to 12 (#335).

Added

  • Layered text output format (#333) (render::text::format_record, --format text): one human-readable, indented block per MRT record — session context (TIME/TYPE/FROM/TO), UPDATE: sections with withdrawn/announced prefixes (including those carried in MP_REACH/MP_UNREACH) and every path attribute, OPEN: capabilities, session states, RIB entries, the peer table, and full legacy type-5 records. RFC 7606 validation findings render under WARNINGS: when present. The format is designed around this crate's own models and Display vocabulary — inspired by bgpdump's human-readable output, not byte-compatible with it. Rendering is a pure function of the record. In the CLI, --format text always uses record-level output (implies --level records); the other formats follow --level and default to elems.
  • --hex flag (#334): include each record's original wire bytes as hex in record-level output — a HEX: line at the end of --format text blocks, a hex field in --format json/json-pretty records. Designed as the pipe from filtered CLI output into byte-level tools (e.g. wirescope's hex paste input): bgpkit-parser -p 8.8.8.0/24 --format text --hex updates.mrt.gz yields blocks whose HEX: line can be pasted straight into a dissector. Bytes come from a new library iterator, BgpkitParser::into_filtered_raw_record_iter() — raw MRT records with the same record-level filter semantics as into_record_iter, yielding the untouched original bytes (no re-encoding, so attribute-ordering quirks such as BGP-LS hash-map iteration can never alter the output). The flag implies --level records, requires text/json/json-pretty formats, is mutually exclusive with --recover, and is ignored by count-only runs (-e/-r), which keep the normal counting pipelines and their per-elem filter semantics.
  • Record-level filter semantics are now explicit (#334): records that produce no elems (KEEPALIVE, OPEN, NOTIFICATION, state changes) never match elem-oriented filters and are dropped from record iteration while filters are active — a debug! line notes each drop.
  • NextHopAddress text form and scope-aware accessors (#339): FromStr parses a single address or a comma-joined RFC 2545 pair (stored positionally as Ipv6LinkLocal); global_addr() resolves a pair by scope rather than position, and link_local_addr() returns the link-local half, if any.

Fixed

  • RIS Live link-local next hops no longer drop UPDATEs (#339): an RFC 2545 global + link-local pair arrives as one comma-joined string ("next_hop": "2001:db8::1,fe80::1"), which failed IpAddr deserialisation; because RisMessage::msg is a flattened Option, the error surfaced as msg: None and the frame's announcements and withdrawals were silently discarded — ~20% of UPDATE frames (15,706 of 77,075 in a 20-second full-feed capture on 2026-09-10). next_hop is now kept verbatim; parse_ris_live_message resolves pairs by scope and returns ElemIncorrectIp for unparseable values instead of silently returning no elems. Regression fixtures with captured frames live in tests/fixtures/rislive/; tests/rislive_frames.rs also cross-checks the JSON and raw-bytes parsers against each other.
  • Two-address next hops resolve by scope in elem conversion (#339): the MRT/raw path took the first address of an Ipv6LinkLocal/VpnIpv6LinkLocal next hop positionally, so a pair with the link-local address first yielded fe80::. The MRT/raw path, the RIS Live JSON path, and Nlri::next_hop_addr() now share NextHopAddress::global_addr().
  • BGP-LS next hops resolve RFC 2545 pairs by scope (#340): parse_link_state_nlri took the first address of an Ipv6LinkLocal/VpnIpv6LinkLocal next hop positionally, so a reversed pair put the link-local address in the BGP-LS NLRI; it now uses NextHopAddress::global_addr(), matching the other elem conversion paths.
  • RIS Live peer-state message type (#338): the live stream sends peer-state messages with "type": "STATE", not "type": "RIS_PEER_STATE" as documented in the RIPE RIS Live documentation and schema. RisMessageEnum::RIS_PEER_STATE now deserializes from both STATE and RIS_PEER_STATE and serializes as STATE, matching the live stream. To be re-validated against RIPE's documentation and schema on/after January 2027.

Contributors

  • @ties — RIS Live peer-state message type (#338), comma-joined IPv6 next hops and scope-resolved next-hop conversion (#339)