# Changelog
All notable changes to this project will be documented in this file.
## v0.20.0 - 2026-08-16
### Breaking changes
* **Fallible encoding** ([#313](https://github.com/bgpkit/bgpkit-parser/issues/313)): all encode paths now return `Result<_, EncodingError>` instead of silently truncating values that do not fit their wire-format fields. There are no panicking wrappers; callers that want the old "just give me bytes" ergonomics can `.unwrap()`. Migration table:
| Before | After |
| --- | --- |
| `Attribute::encode(asn_len) -> Bytes` | `-> Result<Bytes, EncodingError>` (also `encode_to(asn_len, &mut BytesMut)`) |
| `Attributes::encode(asn_len) -> Bytes` | `-> Result<Bytes, EncodingError>` (also `encode_to`) |
| `BgpOpenMessage::encode() -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `BgpUpdateMessage::encode(asn_len) -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `BgpMessage::encode(asn_len) -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `TableDumpMessage::encode() -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `RibEntry::encode()` / `RibAfiEntries::encode() -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `PeerIndexTable::encode()` / `GeoPeerTable::encode() -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `PeerIndexTable::add_peer(peer) -> u16` | `-> Result<u16, EncodingError>` (rejects the 65,536th peer instead of wrapping the id) |
| `MrtMessage::encode(sub_type)` / `Bgp4MpMessage::encode(asn_len)` / `MrtRecord::encode() -> Bytes` | `-> Result<Bytes, EncodingError>` |
| `MrtRibEncoder::process_elem(&elem)` | `-> Result<(), EncodingError>` |
| `MrtRibEncoder::export_bytes()` / `MrtUpdatesEncoder::export_bytes() -> Bytes` | `-> Result<Bytes, EncodingError>` |
`EncodingError` has two variants: `ValueTooLarge { field, actual, max }` for wire-capacity overflows and `Unencodable { field, reason }` for values with no valid wire representation (ATTR_SET, RIB_GENERIC, OPEN parameter type 255, labeled NLRI with an empty label stack).
* **Legacy MRT enum variants**: `MrtMessage` gains `TableDumpMessageBatch` and `LegacyBgp`, and `MrtUpdate` gains `LegacyBgpUpdate`. Downstream exhaustive matches must handle the new variants.
* **Traffic Engineering attribute variant**: `AttributeValue` gains `TrafficEngineering` ([#290](https://github.com/bgpkit/bgpkit-parser/issues/290)). The code-24 BGP Traffic Engineering attribute (RFC 5543), previously raw-retained, now parses to this typed variant. Downstream exhaustive matches must handle the new variant.
* **Link Bandwidth extended community variant**: `ExtendedCommunity` gains `LinkBandwidth` ([#299](https://github.com/bgpkit/bgpkit-parser/issues/299)). Two-octet AS-specific extended communities with subtype 0x04 (RFC 10005 link bandwidth) now parse to this variant instead of `TransitiveTwoOctetAs` / `NonTransitiveTwoOctetAs`, changing their `Display` and serde representations (wire encoding is byte-identical). Downstream exhaustive matches must handle the new variant.
* **`Tlv::length()` and `SubTlv::length()` removed**: both silently saturated at `u16::MAX`; encoders now compute checked lengths internally.
* **`OptParam` no longer has a `param_len` field**: the field was redundant now that the encoder always derives the wire length from `param_value`, and the parser recomputes it on read. Construct `OptParam` with just `param_type` and `param_value`.
* **Quagga BGP states**: `BgpState` gains the implementation-specific `Clearing` and `Deleted` variants for wire values 7 and 8. Downstream exhaustive matches must handle the new variants.
* **ROUTE-REFRESH message variant**: `BgpMessage` gains `RouteRefresh(BgpRouteRefreshMessage)` and `BgpMessageType` gains `ROUTE_REFRESH` for BGP message type 5 (RFC 2918), previously rejected as "Unknown BGP Message Type". Downstream exhaustive matches must handle the new variants.
### Added
#### Parser interfaces
* **Unified MRT/text-dump parser API** ([#321](https://github.com/bgpkit/bgpkit-parser/pull/321)): `BgpkitParser` gains three new constructor groups that integrate text dumps into the standard `for elem in parser` iteration loop. `new_text(path)` / `from_text_reader(r)` parse a known text dump; `new_auto(path)` / `from_auto_reader(r)` peek the first bytes and auto-dispatch to the text or MRT path. Both text-dump paths **stream elements lazily** — one route line at a time, constant memory — via a new `TextDumpElemIterator`. All existing filter methods (`add_filter`, `with_filters`, etc.) work on both paths. The default `new(path)` constructor remains MRT-only.
* **Diagnostic MRT iterator** ([#324](https://github.com/bgpkit/bgpkit-parser/pull/324), [#303](https://github.com/bgpkit/bgpkit-parser/issues/303)): added `into_diagnostic_iter()` for record-level malformed-data investigation. It emits clean records, recoverable RFC 7606 validation findings with original MRT bytes, and fatal parse errors with available header and byte context.
* **Experimental resumable HTTP reader** ([#323](https://github.com/bgpkit/bgpkit-parser/pull/323)): `BgpkitParser::new_resumable_http` uses oneio's range-request reader to resume interrupted HTTP(S) downloads without changing the behavior of `new`. Unsupported Range requests or inconsistent resumed responses return an error ([#288](https://github.com/bgpkit/bgpkit-parser/issues/288)).
* **Cisco `sh ip bgp` text dump parsing** ([#320](https://github.com/bgpkit/bgpkit-parser/issues/320)): new `parser::text_dump` module parses fixed-width text RIB dumps published by PCH (daily routing table snapshots) and route-views (`oix-full-snapshot-*.bz2`) into `BgpElem`s. Column offsets are derived from the table header so blank numeric columns (Metric, LocPrf, Weight) stay distinct from AS-path data; multipath continuation lines and wrapped prefixes (including IPv6) are supported. Route-views dumps without the `BGP table version` / `local AS` preamble parse with sentinel peer identity (`0.0.0.0` / AS0) ([#321](https://github.com/bgpkit/bgpkit-parser/pull/321)). Also provides `detect_text_dump` for format sniffing and `infer_timestamp_from_path` for PCH (`YYYY.MM.DD`) and route-views (`YYYY-MM-DD-HHMM`) file-name timestamps. Ported from monocle ([#143](https://github.com/bgpkit/monocle/pull/143), [#146](https://github.com/bgpkit/monocle/pull/146)).
#### Protocol support
* **Early RIPE RIS MRT support** ([#316](https://github.com/bgpkit/bgpkit-parser/pull/316)): Parse deprecated MRT Type 5 BGP OPEN, UPDATE, NOTIFY, KEEPALIVE, and STATE_CHANGE records, along with historical TABLE_DUMP v1 records that batch multiple entries and declare their physical length four bytes short. Record iteration preserves each physical TABLE_DUMP batch while element, update, and route iteration expands its entries.
* **RFC 5543 Traffic Engineering attribute** ([#322](https://github.com/bgpkit/bgpkit-parser/pull/322)): Typed parsing and encoding for the BGP Traffic Engineering attribute (type 24) ([#290](https://github.com/bgpkit/bgpkit-parser/issues/290)). Exposes the Switching Capability, Encoding, Reserved, and eight Maximum LSP Bandwidth fields (IEEE-754), and retains switching-capability-specific information as raw bytes with wire-faithful round-trip.
* **RFC 2918 ROUTE-REFRESH messages** ([#326](https://github.com/bgpkit/bgpkit-parser/pull/326)): Parse and encode BGP ROUTE-REFRESH messages (type 5) found in RIS BGP4MP update archives. AFI and SAFI are kept as raw integers so refreshes for address families outside the typed enums still round-trip byte-for-byte; the reserved byte is exposed as the RFC 7313 message subtype and trailing ORF data (RFC 5291) is retained raw. ROUTE-REFRESH records yield no elements. RFC 7313 Section 5 findings — an unknown message subtype, or a BoRR/EoRR message whose body is not exactly 4 bytes — surface as new `BgpValidationWarning` variants (`UnknownRouteRefreshSubtype`, `InvalidRouteRefreshLength`) through `BgpRouteRefreshMessage::validation_warnings()` and the diagnostic iterator, while the message itself is retained.
* **RFC 10005 Link Bandwidth Extended Community** ([#319](https://github.com/bgpkit/bgpkit-parser/pull/319)): Typed parsing and encoding for the BGP Link Bandwidth Extended Community in both transitive (`0x00`) and non-transitive (`0x40`) forms ([#299](https://github.com/bgpkit/bgpkit-parser/issues/299)). Exposes the Global Administrator, bandwidth in bytes per second, and transitivity, and preserves the wire type on encode.
* **Updated `bgpkit-broker` dependency from 0.11 to 0.12** ([#318](https://github.com/bgpkit/bgpkit-parser/pull/318)).
* **Fixed standalone `cli` feature**: `cargo build --no-default-features --features cli` now compiles; the CLI binary was previously broken in that combination because `BgpkitParser::new`/`new_cached` require `oneio` (broken since at least v0.18.0, and not covered by any CI feature combination). TLS backend selection is unchanged: standalone `cli` enables `oneio`'s plain-HTTP reader, and `cli,rustls` / `cli,native-tls` select a backend additively as before.
#### Test data
* **Historical RIPE regression fixtures** ([#316](https://github.com/bgpkit/bgpkit-parser/pull/316)): Added original RRC00 update and bview gzip files from 1999 and January 2000 as repository-only, offline integration fixtures.
* **PacketLife ORF capture fixture** ([#326](https://github.com/bgpkit/bgpkit-parser/pull/326)): Added the PacketLife.net "bgp orf prefix advertisement" capture (via <https://github.com/epiecs/packetlife-backup>) as a repository-only fixture exercising ROUTE-REFRESH with RFC 5291 ORF payload bytes extracted from the pcapng TCP stream.
* **Opt-in MRT framing recovery** ([#325](https://github.com/bgpkit/bgpkit-parser/pull/325)): Added `into_recovering_record_iter`, `into_recovering_elem_iter`, and CLI `--recover` support for salvaging records after damaged MRT framing. Recovery validates a three-record chain, uses exact embedded BGP headers as BGP4MP anchors, and reports every skipped decompressed byte range as a typed gap event. A record of any MRT type whose framing is intact but whose body fails to parse is skipped exactly (`AlignedRecordChain` evidence) when intact records follow its declared boundary, and damage extending to the end of the stream — e.g. a truncated final record — is reported as a terminal gap (`EndOfStream` evidence) instead of an error. Text-dump parsers, which have no MRT record representation, yield an explicit `Unsupported` error.
#### Examples
* **Diagnostic MRT iterator example** ([#324](https://github.com/bgpkit/bgpkit-parser/pull/324)): Added `examples/diagnostic_iterator.rs` to classify clean records, RFC 7606 validation findings, and fatal parse errors while exporting raw MRT bytes for each finding.
* **Resumable HTTP reader example** ([#323](https://github.com/bgpkit/bgpkit-parser/pull/323)): Added `examples/resumable_http.rs` to parse a remote MRT file with `new_resumable_http` and report unrecoverable read failures.
### Fixed
* **Fallible MRT error bytes** ([#315](https://github.com/bgpkit/bgpkit-parser/pull/315)): Header, oversized-record, partial-body, and route-iterator failures now retain all consumed record bytes. Default/raw iteration only writes `mrt_core_dump` when explicitly enabled, and raw error skipping no longer recurses.
* **Silent truncation on encode eliminated** ([#313](https://github.com/bgpkit/bgpkit-parser/issues/313)): AS_PATH segments with >255 ASes, attribute values exceeding their (extended or non-extended) length field, TLV values in Tunnel Encapsulation / BGP-LS / SFP / BFD Discriminator / Prefix-SID / BIER attributes, RIB entry counts, peer counts, view names, and BGP message total lengths now return `EncodingError` instead of writing corrupt length fields.
* **FlowSpec NLRI length bound**: the wire length field is 12-bit (RFC 8955); NLRI data of 4096..=65535 bytes previously passed an unchecked `u16` cast and encoded a corrupt length byte. It is now rejected with `ValueTooLarge`.
* **MP_REACH/MP_UNREACH encoding errors are no longer swallowed**: labeled-NLRI failures previously logged a warning and emitted a zero-length (RFC-invalid) attribute value; they now propagate as `EncodingError`.
* **FlowSpec NLRI entries are now encoded**: `Nlri::flowspec_nlris` was previously silently dropped when encoding MP_REACH/MP_UNREACH attributes.
* **Peer index aliasing**: `PeerIndexTable::add_peer` previously wrapped the peer id at 65,536 peers, silently attributing routes to the wrong peer; it now returns an error and leaves the table unmodified.
* **BGP OPEN parameter type 255 rejected**: RFC 9072 reserves type 255 as the extended-length marker; encoding it as a real parameter produced output that round-tripped to a structurally different message.
* **BGP OPEN optional-parameter encoding**: Encode the Optional Parameters Length as the total byte length required by RFC 4271 instead of the number of parameters. OPEN messages now also use the extended length format from RFC 9072 when requested or required.
* **Historical Quagga state changes**: Parse BGP4MP state-change records containing Quagga's `Clearing` (7) and `Deleted` (8) FSM states instead of logging an error and dropping the MRT record.
* **CLI broken-pipe exit status** ([#325](https://github.com/bgpkit/bgpkit-parser/pull/325)): the CLI now exits 0 when its stdout consumer closes the pipe early (e.g. `bgpkit-parser updates.gz | head`), matching Unix convention; previous releases exited 1. Other write errors still exit 1.
### Contributors
* @ties — fallible encoding and MRT error-handling overhaul ([#312](https://github.com/bgpkit/bgpkit-parser/pull/312), [#315](https://github.com/bgpkit/bgpkit-parser/pull/315)), early RIPE RIS MRT support ([#316](https://github.com/bgpkit/bgpkit-parser/pull/316)), historical Quagga BGP states ([#317](https://github.com/bgpkit/bgpkit-parser/pull/317)), recovering parser ([#325](https://github.com/bgpkit/bgpkit-parser/pull/325)), ROUTE-REFRESH parsing ([#326](https://github.com/bgpkit/bgpkit-parser/pull/326))
* @downwithbgp — RFC 10005 Link Bandwidth Extended Community support ([#319](https://github.com/bgpkit/bgpkit-parser/pull/319)), RFC 5543 Traffic Engineering attribute support ([#322](https://github.com/bgpkit/bgpkit-parser/pull/322))
* @digizeph — unified MRT/text-dump parser API ([#321](https://github.com/bgpkit/bgpkit-parser/pull/321)), resumable HTTP parser ([#323](https://github.com/bgpkit/bgpkit-parser/pull/323)), diagnostic MRT iterator ([#324](https://github.com/bgpkit/bgpkit-parser/pull/324))
## v0.19.0 - 2026-07-28
### Breaking changes
* **`BgpValidationWarning` is now `#[non_exhaustive]`**: Exhaustive `match` on this enum must add a `_` arm. This allows new warning variants to be added in future minor releases without breaking downstream matches.
### Added
* **Extended element filtering**: Added `Filter` variants for nine previously unfilterable `BgpElem` fields: `only_to_customer` (`otc`), `next_hop`, `origin`, `local_pref`, `med`, `atomic`, `aggr_asn`, `aggr_ip`, and `peer_bgp_id`. Each optional field also supports presence filtering via the `*` wildcard — e.g. `otc=*` matches elements that carry an OTC value, `otc=!*` matches elements without one. ([#306](https://github.com/bgpkit/bgpkit-parser/issues/306))
* **RFC 7606 non-fatal NLRI parsing**: Malformed NLRI fields (withdrawn or announced) no longer cause the entire BGP UPDATE message to be discarded. Instead, the parser returns the UPDATE with partial prefix data and records a `BgpValidationWarning::MalformedNlri` warning containing the raw NLRI bytes, enabling callers to emulate RFC 7606 treat-as-withdrawal semantics. Attribute framing errors (truncated length fields, inconsistent data) remain fatal. ([#303](https://github.com/bgpkit/bgpkit-parser/issues/303))
* **Treat-as-withdrawal example**: Added `examples/treat_as_withdrawal.rs` demonstrating how to scan MRT files for RFC 7606 validation issues, classify them by error-handling category (attribute discard vs. treat-as-withdrawal), and extract raw malformed NLRI bytes.
* **MRT attribute code counter example**: Added `examples/count_attributes.rs`, which reports every parsed BGP path-attribute wire code in a local or remote MRT file, including raw-retained unsupported, deprecated, and unassigned attributes.
* **RTR PDU fuzzer**: Added `fuzz_rtr` fuzz target for RPKI RTR PDU parsing. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
### Fixed
* **Raw bytes preserved on MRT body-parse failures**: `parse_mrt_record` now attaches the original MRT record bytes to `ParserErrorWithBytes.bytes` when the message body fails to parse, enabling forensic analysis and record export. Previously `bytes` was always `None` for body-level failures. ([#303](https://github.com/bgpkit/bgpkit-parser/issues/303))
* **FlowSpec prefix parsing OOB**: Reject FlowSpec prefix lengths > 128 before copying address bytes, preventing an out-of-bounds panic on the fixed 16-byte IPv6 buffer. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **RTR Error Report oversized text panic**: Validate the declared `error_text_len` fits within the PDU before slicing, preventing an out-of-bounds panic from a crafted length field. The `encap_pdu_len` check was also switched to subtraction to avoid `usize` overflow on 32-bit targets. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **RTR PDU memory-exhaustion DoS**: Cap RTR PDU allocations at `RTR_MAX_ERROR_REPORT_LEN` (~128 KiB) before allocating, so a crafted `length` header cannot drive a multi-gigabyte allocation. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **BGP4MP Link-State AFI rejection**: Reject `Afi::LinkState` in BGP4MP envelopes (Message, StateChange, route parsing), which previously fell through to an incorrect IPv4-format assumption. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **BGP4MP payload length underflow**: Switched `bgp4mp_message_payload_len` to saturating subtraction and made it fallible, preventing underflow on truncated/inconsistent records. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **OpenBMP admin-id clamp**: Removed the 255-byte clamp on `admin_id` length in OpenBMP header parsing; the declared length is now consumed in full to avoid misparsing subsequent fields. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
* **AS path allocation overflow guard**: Validate ASN byte count via `checked_mul` before allocating in `read_asns`, preventing overflow-driven pre-allocation on 32-bit targets from a crafted count. ([#308](https://github.com/bgpkit/bgpkit-parser/pull/308))
### Changed
* **NLRI parse errors are now non-fatal**: `parse_bgp_update_message` previously returned `Err` on any malformed NLRI byte, discarding all attributes and partially-parsed prefixes. It now returns `Ok` with partial data and a `BgpValidationWarning::MalformedNlri`. This is the correct RFC 7606 behavior — callers should check `attributes.validation_warnings()` if they need to distinguish clean updates from partially-recovered ones.
* **Examples documentation**: Expanded `examples/README.md` to index all maintained Rust, standalone, and WebAssembly examples. Refreshed standalone example instructions, corrected the RIB entry age study path, and made selected archive examples accept input sources or archive months.
* **Dependency: oneio updated from 0.23 to 0.24**: Brings S3 multipart upload retry with exponential backoff, `ONEIO_S3_MAX_RETRIES` / `ONEIO_S3_RETRY_BACKOFF_MS` env vars, per-request upload timeout, and zstd compression support (`.zst` suffix). ([#305](https://github.com/bgpkit/bgpkit-parser/pull/305))
## v0.18.0 - 2026-07-02
### Breaking changes
* **`AttrRaw` fields changed**: `attr_type: AttrType` replaced with `code: u8`. Use `.attr_type()` to get the `AttrType` back. `bytes` changed from `Vec<u8>` to `Bytes`.
* **`AttrType::CLUSTER_ID` removed**: Code 13 is the deprecated `RCID_PATH / CLUSTER_ID` per IANA registry and is now retained as `AttributeValue::Deprecated`.
* **`AttributeValue` gains new variants**: `Raw(AttrRaw)`, `BfdDiscriminator(...)`, `BgpPrefixSid(...)`, `Bier(...)`, `Sfp(...)`. Downstream exhaustive matches must handle these.
* **`AigpTlv.value` changed**: From `Vec<u8>` to `Bytes`.
* **No more silent attribute loss**: Known-but-unsupported attributes that were previously dropped are now retained as `AttributeValue::Raw(AttrRaw)`. If your code expected these to be absent, it may now see them.
### New features
* **RIS Live raw message parsing**: Added `parse_ris_live_message_raw()` and `parse_ris_live_message_json()` so users can opt into RIS Live `socketOptions.includeRaw` and parse original BGP wire messages instead of only RIS Live's reduced JSON attribute projection. Raw parsing now validates the full RIS Live `ris_message` envelope and expects standard `id`/`host` fields.
* **RIS Live subscription helpers**: Re-exported `RisSubscribe`, `RisSubscribeType`, and `RisLiveClientMessage` from the crate root, making it easier to request `includeRaw` in examples and downstream code.
* **RIS Live examples**: Updated the synchronous WebSocket example to demonstrate `includeRaw` + raw BGP parsing; kept the async example on JSON-field parsing with comments showing how to opt into raw parsing.
* **Raw attribute retention**: Known BGP path attributes without semantic parsing are no longer silently dropped. They are retained as `AttributeValue::Raw(AttrRaw)` with their original wire code and bytes, enabling faithful re-encoding.
* **Deprecated code point handling**: Removed `AttrType::CLUSTER_ID = 13` (deprecated per IANA); code 13 is now retained as `Deprecated(AttrRaw)`. Added `is_deprecated_attr_type()` helper.
* **`AttrType::BIER` added**: Code 41 (RFC 9793) added to the enum.
* **Typed parser failure fallback**: If a typed attribute parser fails, the original bytes are retained as `AttributeValue::Raw` instead of being dropped. A validation warning is still recorded.
* **Serialization**: Added `serde` feature to `bytes` dependency so `AttrRaw` (with `Bytes`) can be serialized.
### New attribute parsers
* **RFC 7311 — AIGP (code 26)**: Parses AIGP TLVs, preserves unknown TLVs, supports round-trip encoding. Exposes `accumulated_metric()` helper.
* **RFC 9015 — SFP attribute (code 37)**: Parses SFP TLVs with 1-octet type and 2-octet length. Preserves unknown TLVs.
* **RFC 9026 — BFD Discriminator (code 38)**: Parses mode, discriminator, and optional 1-octet TLVs. Preserves unknown optional TLVs.
* **RFC 8669 — BGP Prefix-SID (code 40)**: Parses Prefix-SID TLVs with 1-octet type and 2-octet length. Preserves unknown TLVs.
* **RFC 9793 — BIER (code 41)**: Parses BIER TLVs with 2-octet type and 2-octet length. Preserves unknown TLVs.
### Added
* `AttributeValue::Raw(AttrRaw)` — for known but undecoded attributes.
* `AttrRaw { code: u8, bytes: Bytes }` — stores wire code and raw value bytes.
* `AttributeValue::attr_code()` — returns the raw wire attribute type code as `u8`.
* `AttrRaw::attr_type()` — convenience conversion to `AttrType`.
* Model structs: `BfdDiscriminatorAttribute`, `BgpPrefixSidAttribute`, `BierAttribute`, `SfpAttribute`.
* Raw TLV helper types: `RawTlv8`, `RawTlv8Ext`, `RawTlv16`.
* `examples/raw_attributes.rs` — demonstrates inspecting raw/deprecated/unknown attributes.
### Fixed
* Code 13 (`RCID_PATH / CLUSTER_ID`) no longer maps to an active `AttrType` variant; correctly handled as deprecated.
* Known but unsupported attributes (codes 0, 22, 24, 27, 33, 128) are now retained as `Raw` instead of dropped.
* Malformed typed attributes retain their original bytes as `Raw` after recording a validation warning.
## v0.17.0 - 2026-05-24
### New features
* **Minimal route-level parser**: Added `BgpRouteElem` and `into_route_iter()` / `into_fallible_route_iter()` for fast scans when only prefix, AS path, peer metadata, and timestamp are needed (thanks @ties for the contribution).
- `BgpRouteElem` struct with `Option<Arc<AsPath>>` — shares the same parsed AS path across all announced prefixes from a single BGP UPDATE via `Arc`
- `RouteIterator` and `FallibleRouteIterator` for MRT records (BGP4MP, TableDump v1/v2, IPv4/IPv6, add-path)
- Filter support shared via `RouteFilterView` trait: `origin_asn`, `prefix`, `peer_ip`, `peer_asn`, `type`, `ts_start`/`ts_end`, `as_path`, `ip_version` all match identically to `BgpElem`
- Community filters fail-closed (return no match) since communities are not parsed at the route level
- Trait parity with `BgpElem`: `Display` (PSV-style), `Eq`, `PartialOrd`, `Ord` all implemented
- Performance: ~10-15% faster on updates files, ~50-70% faster on RIB dumps
- Added `examples/route_level_parsing.rs` demonstrating performance comparison
* **RFC 3107/8277 MPLS Labeled NLRI support**: Added parsing and encoding for BGP MPLS Labeled NLRI (SAFI 4) (thanks @ties for the contribution).
Note: RFC 8277 obsoletes RFC 3107; both are supported for compatibility:
- New `MplsLabel` type with label value, TC, S-bit, and TTL
- `LabeledNetworkPrefix` combining prefix with label stack (`SmallVec<[MplsLabel; 2]>`)
- `LabeledNlriConfig` for configurable parsing modes; default is MultiLabel (handles both single and stacked labels)
- `Safi::MplsLabel = 4` added to SAFI enum
- `Nlri` struct (inner type of `MpReachNlri`/`MpUnreachNlri`) updated with `labeled_prefixes` field for MPLS announcements
- Error variants for labeled NLRI parsing failures
### Performance improvements
* **Route-level parsing**: Selective attribute parsing skips communities, MED, next-hop, local-pref, and other attributes not needed for route identity. Combined with `Arc<AsPath>` sharing across prefixes from the same message, this yields ~10-15% faster updates parsing and ~50-70% faster RIB dump parsing.
* **AS Path memory optimization**: Reduced allocations for common cases using `smallvec` (thanks @ties for the contribution):
- `AsPath::segments`: Uses `SmallVec<[AsPathSegment; 1]>` — 99.99% of routes have exactly 1 segment (zero-allocation coverage)
- `AsPathSegment` variants: Uses `SmallVec<[Asn; 6]>` — 90.85% of segments have ≤6 ASNs (zero-allocation coverage)
- Based on RIB analysis of 200K records from route-views2 (3.29M segments analyzed)
### Breaking changes
* **`Nlri` struct**: Added `labeled_prefixes: Option<Vec<LabeledNetworkPrefix>>` field.
This field is `None` for all non-MPLS routes (SAFI ≠ 4) and is populated only when
`safi == Safi::MplsLabel`. If you pattern-match or destructure `Nlri`, add `..` or
handle the new field. No behavior change for existing IPv4/IPv6 unicast parsing.
### Fixed
* **RFC 4760 mandatory attribute validation**: Fixed validation to properly handle multiprotocol BGP (MP-BGP) conditional mandatory attributes (thanks @ties for the contribution):
- Pure withdrawals (no announcements): no mandatory attributes required
- MP_REACH_NLRI only: ORIGIN and AS_PATH required, NEXT_HOP not required (embedded in MP_REACH_NLRI)
- IPv4 NLRI: ORIGIN, AS_PATH, and NEXT_HOP all required
- Mixed (IPv4 NLRI + MP_REACH_NLRI): ORIGIN, AS_PATH required; NEXT_HOP required because IPv4 NLRI is present
### Added
* **`AttributeValidationState`**: Extracted reusable validation struct from `parse_attributes()` so that both full attribute parsing and route-level parsing share identical RFC 7606 / RFC 4271 validation logic.
* **`RouteFilterView` trait**: New internal trait that enables sharing filter matching logic between `BgpElem` and `BgpRouteElem`. Community filters return `false` for route elements since communities are not parsed.
* **`Attributes::check_mandatory_attributes()`**: New method to validate mandatory attributes with proper NLRI context awareness. Must be called after NLRI parsing to correctly determine requirements.
* **`Attributes::attr_mask`**: Internal `[u64; 4]` bitmask field for O(1) attribute presence tracking (32 bytes vs 256 bytes for `[bool; 256]`)
* **`serde` feature**: Enabled `serde/rc` for `Arc<AsPath>` serialization support in `BgpRouteElem` when the `serde` feature is active.
* **BMP RFC 9515, 9736, 9972 support**:
- RFC 9972: Added 26 new `StatType` variants for advanced Adj-RIB-In/Adj-RIB-Out monitoring statistics (types 18–43)
- RFC 9736: Separated Peer Up TLV namespace from Initiation TLVs; both enums now use `FromPrimitive` with catch-all `Unknown(u16)` for forward compatibility with unassigned types
- RFC 9515: Documentation-only update (registration procedures changed to "First Come First Served")
* **Integration tests**: Added `tests/test_bgp_update_validation.rs` with comprehensive scenario coverage for all validation cases
* **Example `examples/parse_bmp_mpls.rs`**: Demonstrates extracting MPLS-labeled NLRI from BMP Route Monitoring messages, showing how to access label stack information via `MpReachNlri` attribute
### Changed
* **`parse_attributes()`**: Removed inline mandatory attribute validation; validation now performed by callers via `Attributes::check_mandatory_attributes()` after NLRI context is known
* **`Attributes::has_attr()`**: Now O(1) via bitmask lookup instead of O(n) vector scan
* **`Attributes` Debug impl**: Changed from derived to manual implementation (excludes internal `attr_mask` field)
* **All `Attributes` constructors**: Updated to compute and populate `attr_mask` from `inner` vector
## v0.16.0 - 2026-04-07
### Breaking changes
* **`BgpOpenMessage::sender_ip` renamed to `bgp_identifier`**: The field type remains `Ipv4Addr` (aliased as `BgpIdentifier`), but the name now correctly reflects RFC 4271 terminology — this is the BGP Identifier, not necessarily the sender's IP address.
### Security improvements
* **AS_PATH segment count validation**: Added bounds check to prevent buffer over-read when parsing AS_PATH segments. Validates that `count * asn_len.bytes()` does not exceed remaining buffer size (CWE-126).
* **BGP message length underflow protection**: Added saturating arithmetic to prevent integer underflow when calculating message length (CWE-191).
* **NLRI prefix length validation**: Enforce maximum prefix lengths (32 bits for IPv4, 128 bits for IPv6) immediately after reading length byte (CWE-20).
* **BGP marker RFC 4271 compliance**: Fixed marker encoding to use 16 bytes of 0xFF as required by RFC 4271. Added validation on parse with warning for non-compliant markers.
* **Communities divisibility validation**: Validate that Communities (4 bytes), Extended Communities (8 bytes), and Large Communities (12 bytes) attribute lengths are properly divisible by their respective sizes.
* **FlowSpec traffic rate validation**: Added NaN and infinity checks for FlowSpec Traffic Rate extended communities to prevent undefined behavior in downstream calculations.
* **FlowSpec DSCP byte offset**: Corrected Traffic Marking extended community parsing per RFC 5575 (DSCP at proper byte offset).
* **Production code safety**: Replaced `assert_eq!` with `debug_assert_eq!` in production parsing code to prevent panics on malformed input.
* **Timestamp overflow handling**: Fixed timestamp truncation for values beyond 2106 (u32::MAX) using proper bounds checking.
* **Encoding truncation checks**: Added overflow warnings for `as u8`/`as u16` casts in encoding functions.
* **IPv4 enforcement for AGGREGATOR/ORIGINATOR_ID**: Encoders now reject IPv6 addresses for these attributes (BGP specifications require IPv4 only).
### New features
* **WebAssembly (WASM) support (experimental)**: New `wasm` feature flag compiles the BMP/BGP/MRT parsing core to WebAssembly for use in JavaScript environments. Published as [`@bgpkit/parser`](https://www.npmjs.com/package/@bgpkit/parser) on npm with support for Node.js (CommonJS), bundlers (ES modules), and browsers/workers (ES modules with manual init). This feature is experimental and the API may change in future releases.
- Core parsing functions (all platforms):
- `parseOpenBmpMessage(data)`: parses OpenBMP-wrapped BMP frames (e.g. RouteViews Kafka stream)
- `parseBmpMessage(data, timestamp)`: parses raw BMP frames (without an OpenBMP header)
- `parseBgpUpdate(data)`: parses a single BGP UPDATE message into `BgpElem[]`
- `parseMrtRecords(data)`: streaming generator that yields MRT records one at a time from a decompressed buffer
- `parseMrtRecord(data)` / `resetMrtParser()`: low-level MRT record parsing
- Node.js I/O helpers:
- `streamMrtFrom(pathOrUrl)`: fetch, decompress (gz/bz2), and stream-parse MRT records from a URL or local file
- `openMrt(pathOrUrl)`: fetch and decompress MRT data into a `Buffer`
- Supports gzip (RIPE RIS) and bzip2 (RouteViews, requires optional `seek-bzip` dependency) compression
- Multi-target build script (`src/wasm/build.sh`) produces nodejs, bundler, and web targets in a single npm package
- JS wrapper handles JSON deserialization; TypeScript types included
- Node.js examples in `examples/wasm/`: Kafka OpenBMP stream consumer and MRT file parser
- Browser-based MRT explorer demo: [mrt-explorer.labs.bgpkit.com](https://mrt-explorer.labs.bgpkit.com/)
* **`BgpElem::peer_bgp_id` field**: `BgpElem` now exposes an optional `peer_bgp_id: Option<BgpIdentifier>` containing the peer's BGP Identifier (Router ID) when available. Populated from the PEER_INDEX_TABLE in TableDumpV2/RIB records; `None` for BGP4MP records.
* **`with_filters` and `add_filters` methods**: Added new methods to `BgpkitParser` for passing pre-built `Vec<Filter>` directly, addressing issue #271.
- `with_filters(filters: &[Filter])` - replaces all existing filters with the provided slice; clones internally so no manual clone needed
- `add_filters(filters: &[Filter])` - extends existing filters with the provided slice
- Both methods enable building filter specifications independently and reusing them across multiple parsers without string parsing overhead
- Added rust documentation to `add_filter` method with complete list of available filter types
Example:
```rust
use bgpkit_parser::BgpkitParser;
use bgpkit_parser::parser::Filter;
let filters = vec![
Filter::new("peer_ip", "185.1.8.65").unwrap(),
Filter::new("type", "w").unwrap(),
];
// Reuse across multiple parsers
let parser1 = BgpkitParser::new(url1).unwrap().with_filters(&filters);
let parser2 = BgpkitParser::new(url2).unwrap().with_filters(&filters);
```
* **Immutable Elementor API**: New methods enable parallel processing of MRT records
- `Elementor::with_peer_table(peer_table)` creates a pre-initialized Elementor
- `Elementor::record_to_elems_iter(&self, record)` returns a lazy iterator without requiring `&mut self`
- `BgpkitParser::into_elementor_and_raw_record_iter()` returns `(Elementor, iterator)` with PeerIndexTable pre-extracted
- `BgpkitParser::into_elementor_and_record_iter()` returns `(Elementor, iterator)` with PeerIndexTable pre-extracted
- New `RecordElemIter` and `BgpUpdateElemIter` types for lazy element iteration
- New `ElemError` type for explicit error handling
- Parallel processing example demonstrating multi-threaded parsing with significant speedup
### Performance improvements
* **Memory usage reduction (61% improvement)**: Optimized memory allocation patterns resulting in significant peak memory reduction:
- **NLRI Add-Path clone-free parsing**: Replaced input buffer cloning with speculative byte-slice parsing. The new `try_parse_prefix` function parses from a byte slice without consuming, returning `(prefix, bytes_consumed)`. The `read_nlri_prefix` method is now a thin wrapper that calls `try_parse_prefix` and advances the cursor. This eliminates the expensive `input.clone()` operation while maintaining correct Add-Path heuristic retry behavior.
- **Attribute vector pre-allocation**: Estimate capacity from data size (`remaining / 3` bytes per attribute) instead of fixed 20, reducing reallocations for BGP messages with many attributes.
- **RIS Live vector pre-allocation**: Calculate capacity from announcements + withdrawals counts before allocation, preventing growth reallocations.
- **Measured improvement**: Peak memory reduced from 2,037 MB to 789 MB (61.3% reduction) when parsing full BGP table dump (RouteViews LINX RIB, 151MB compressed).
- **Code quality**: Single implementation of prefix parsing logic in `try_parse_prefix`, eliminating duplication with `read_nlri_prefix`.
* Use zerocopy for MRT header parsing
- Replaced manual byte parsing with zerocopy's `FromBytes` trait for `RawMrtCommonHeader` and `RawMrtEtCommonHeader`
- Reduces bounds checking overhead by using compile-time verified struct layouts
- Added compile-time assertions to ensure header sizes match wire format (12 bytes standard, 16 bytes ET)
- Encoding now uses zerocopy's `IntoBytes` trait for efficient byte conversion
* Use zerocopy for BGP OPEN message and capability parsing
- `RawBgpOpenHeader` (10 bytes), `RawMultiprotocolExtensions` (4 bytes), and `RawFourOctetAs` (4 bytes) use zerocopy struct layouts
- Replaces sequential cursor reads with single bounds-checked struct references
### Code improvements
* **Enhanced warning messages**: Added context to 14 warning messages across BGP, BMP, and MRT parsers to help identify which parsing stage encountered an issue. Also fixed typo in NLRI warning ("NRLI" → "NLRI").
* **Codecov configuration**: Added `require_base: true` to ensure Codecov only posts coverage reports when a valid base commit coverage exists, preventing comparisons against outdated baselines.
### Bug fixes
* **WASM `only_to_customer` serialization**: Added test to verify that messages without the OTC (Only To Customer) attribute correctly serialize `only_to_customer` as `null` (not `0`) in JSON output. This ensures JavaScript consumers can properly distinguish between "no OTC attribute" (`null`) and "OTC with AS 0" (`0`).
* **OTC attribute on withdrawal messages**: Withdrawal elements no longer inherit the `only_to_customer` value from their associated UPDATE message. Since the OTC attribute (RFC 9234) is used for route leak detection on route advertisements, it is not semantically meaningful for withdrawals. Withdrawal elements now correctly have `only_to_customer: null`.
* Fix `Attributes::from_iter` for `AttributeValue` to apply default BGP attribute flags instead of empty flags
- Prevents malformed encoding for well-known mandatory attributes such as `ORIGIN` and `AS_PATH`
* Preserve add-path `path_id` when encoding TABLE_DUMP_V2 RIB entries and emit add-path RIB subtypes from `MrtRibEncoder` when entries carry path IDs
* Encode BGP4MP ASNs using the subtype-selected ASN width and always refresh MRT header lengths during record encoding
### Testing
* Added benchmarks for `into_raw_record_iter` for both updates and RIB dumps
## v0.15.0 - 2026-01-28
### Breaking changes
* **Negative Filter Syntax Change**: Negative filters now use value-based negation instead of type-based negation
- Old syntax (v0.14.0): `.add_filter("!origin_asn", "13335")` - **no longer supported**
- New syntax: `.add_filter("origin_asn", "!13335")` - prefix the value with `!`
- For multi-value filters, prefix each value: `.add_filter("origin_asns", "!13335,!15169")`
- Mixing positive and negative values in the same filter is not allowed and will return an error
- CLI syntax remains the same: `--filter "origin_asn!=13335"` (internally converted to value-based negation)
### New features
* **OR Logic Filters**: New filter types that accept comma-separated values with OR logic
- `origin_asns`: Match elements from ANY of the specified origin ASNs
- `prefixes`: Match elements for ANY of the specified prefixes (also supports `prefixes_super`, `prefixes_sub`, `prefixes_super_sub`)
- `peer_asns`: Match elements from ANY of the specified peer ASNs
- `peer_ips`: Now validates input and requires at least one IP address
- Example: `.add_filter("origin_asns", "13335,15169,8075")` matches elements from Cloudflare, Google, or Microsoft
- All multi-value filters support negation with `!` prefix on each value
- New example `multiple_filters_or_logic.rs` demonstrating OR logic and negative filters
## v0.14.0 - 2025-12-22
### New features
* **Negative Filter Support**: Most filters now support negation by prefixing the filter type with `!`
- `!origin_asn`: Match elements where origin AS is NOT the specified value
- `!prefix`: Match elements where prefix is NOT the specified value
- `!peer_ip`, `!peer_asn`, `!type`, `!as_path`, `!community`, `!ip_version`: All support negation
- Note: Timestamp filters (`ts_start`, `ts_end`) do not support negation
- Example: `.add_filter("!origin_asn", "13335")` matches all elements NOT from AS 13335
- New `Filter::Negated(Box<Filter>)` variant wraps any filter to invert its match result
- **CLI**: New `--filter` / `-f` option supports both positive and negative filter expressions
- Positive: `--filter "origin_asn=13335"`
- Negative: `--filter "origin_asn!=13335"`
- Can be used multiple times: `--filter "peer_ip!=192.168.1.1" --filter "type!=w"`
* **RPKI RTR Protocol Support**: Add full support for the RPKI-to-Router (RTR) protocol
- New `models::rpki::rtr` module with all PDU types: SerialNotify, SerialQuery, ResetQuery, CacheResponse, IPv4Prefix, IPv6Prefix, EndOfData, CacheReset, RouterKey, ErrorReport
- New `parser::rpki::rtr` module with parsing (`parse_rtr_pdu`, `read_rtr_pdu`) and encoding (`RtrEncode` trait)
- Support for both RTR v0 ([RFC 6810](https://datatracker.ietf.org/doc/html/rfc6810)) and v1 ([RFC 8210](https://datatracker.ietf.org/doc/html/rfc8210))
- Comprehensive error handling with `RtrError` enum
- New example `rtr_client.rs` demonstrating RTR client implementation with ROA fetching and route validation
## v0.13.0 - 2025-12-07
### Breaking changes
* **`RawMrtRecord` field renamed**: `raw_bytes` is now `message_bytes` to clarify it contains only the message body
- Added new `header_bytes` field containing the raw header bytes as read from the wire
- The `raw_bytes()` method now returns complete MRT record bytes (header + body) without re-encoding
### New features
* Add MRT record debugging and raw bytes export capabilities
- `RawMrtRecord` now stores both `header_bytes` and `message_bytes` to enable exact byte-for-byte export without re-encoding
- New methods on `RawMrtRecord`: `raw_bytes()`, `write_raw_bytes()`, `append_raw_bytes()`, `total_bytes_len()`
- Added `Display` implementations for `MrtRecord`, `CommonHeader`, and `MrtMessage` for human-readable debug output
- New examples: `mrt_debug.rs` and `extract_problematic_records.rs` demonstrating debug features
* CLI now supports record-level output and multiple output formats
- New `--level` (`-L`) option: `elems` (default) or `records` to control output granularity
- New `--format` (`-F`) option: `default`, `json`, `json-pretty`, or `psv`
- Record-level output with `--level records` outputs MRT records instead of per-prefix elements
- JSON output for records provides full structured data for debugging
* Add `UpdateIterator` and `FallibleUpdateIterator` for iterating over BGP announcements ([#250](https://github.com/bgpkit/bgpkit-parser/issues/250))
- New `MrtUpdate` enum supporting both BGP4MP UPDATE messages and TableDumpV2 RIB entries
- `Bgp4MpUpdate` struct for BGP4MP UPDATE messages with metadata (timestamp, peer_ip, peer_asn)
- `TableDumpV2Entry` struct for RIB dump entries (prefix with multiple RIB entries per peer)
- `into_update_iter()` and `into_fallible_update_iter()` methods on `BgpkitParser`
- Middle ground between `MrtRecord` and `BgpElem` for more efficient processing
* Add `update_messages_iter` example demonstrating the new iterator
### Testing and fuzzing
* Add cargo-fuzz harness and initial fuzz targets (mrt_record, bgp_message, parser)
* Add additional fuzz targets (BMP/OpenBMP, RIS Live, attributes, MRT header, NLRI); enable rislive feature for fuzzing
### Bug fixes
* Add bounds checks throughout parsers to avoid overread/advance/split_to panics
* Handle invalid MRT BGP4MP_ET header length gracefully (reject ET records with on-wire length < 4)
* Use originated time instead of MRT header time for TableDumpV2 messages ([#252](https://github.com/bgpkit/bgpkit-parser/pull/252))
* added a new example study `rib_entries_age_study` demonstrating the difference between dump time and entry originated time
### Tooling and benchmarking
* Add hyperfine benchmarking script for bgpkit-parser
## v0.12.0 - 2025-10-17
### Examples and benchmarking
* Added a new runnable example: `examples/parse_single_file_parallel.rs`.
* Parses RIB file using thread pool with batching and collecting. Two modes: worker-only parsing (default) or worker
parsing + element conversion.
* Includes bottleneck diagnostics, tunable parameters (batch size, workers, etc), benchmarking, and remote file
downloading.
### Breaking changes
* change `path_id` from `u32` to `Option<u32>` for proper null handling
* `NetworkPrefix::path_id` field now properly represents absence with `None` instead of using `0`
* `NetworkPrefix::new()` and `NetworkPrefix::encode()` signatures updated accordingly
* `RibEntry` now stores `path_id` for TABLE_DUMP_V2 messages with AddPath support
* fixes issue [#217](https://github.com/bgpkit/bgpkit-parser/issues/217)
### Minumum Supported Rust Version (MSRV)
We now set a minimum supported Rust version (MSRV) of 1.87.0.
### Code improvements
#### New RFCs Supported
* added BGP Flow-Spec parsing support following RFC 8955 and RFC 8956
* implemented complete Flow-Spec NLRI parsing for IPv4 and IPv6 Flow Specification rules
* added support for all Flow-Spec component types (destination/source prefix, protocol, ports, ICMP, TCP flags, packet length, DSCP, fragment, flow label)
* implemented Flow-Spec operator parsing for numeric and bitmask operations with proper semantics
* added Flow-Spec Extended Communities for Traffic Rate, Traffic Action, Redirect, and Traffic Marking (RFC 8955)
* created structured data model with `FlowSpecNlri`, `FlowSpecComponent`, and operator types
* added support for IPv6-specific components including Flow Label and prefix offset encoding
* includes test coverage with RFC example validation and round-trip encoding/decoding
* maintains backward compatibility with existing NLRI and Extended Community parsing infrastructure
* added BGP Tunnel Encapsulation attribute parsing support following RFC 9012, RFC 5640, and RFC 8365
* implemented complete TLV-based parsing system for BGP Tunnel Encapsulation attribute (type 23)
* added support for all IANA-defined tunnel types (VXLAN, NVGRE, GRE, SR Policy, Geneve, etc.)
* added support for all sub-TLV types including Color, UDP Destination Port, Tunnel Egress Endpoint, Preference
* implemented variable-length sub-TLV encoding (1 byte for types 0-127, 2 bytes for types 128-255)
* added helper methods for common attribute access (color, UDP port, egress endpoint, preference)
* created structured data model with `TunnelEncapAttribute`, `TunnelEncapTlv`, and `SubTlv` types
* added comprehensive test coverage with 7 test cases covering parsing, encoding, and error handling
* maintains full backward compatibility with existing attribute parsing infrastructure
* added MRT geo-location extensions support following RFC 6397
* implemented GEO_PEER_TABLE subtype (7) parsing and encoding for TABLE_DUMP_V2 format
* added data structures for collector and peer geo-location information with WGS84 coordinates
* implemented NaN coordinate support for privacy-protected geo-location data
* added `GeoPeerTable` and `GeoPeer` data structures with direct float coordinate storage
* encoding functionality follows consistent parser module pattern with other TABLE_DUMP_V2 types
* includes test coverage with 8 test cases covering parsing, encoding, round-trip operations, and edge cases
* maintains backward compatibility with existing TABLE_DUMP_V2 parsing and encoding infrastructure
* added comprehensive BGP Link-State parsing support following RFC 7752 and extensions
* implemented complete Link-State NLRI parsing for Node, Link, and IPv4/IPv6 Topology Prefix types
* added Link-State AFI (16388) and SAFI (71, 72) support for BGP-LS and BGP-LS-VPN
* implemented TLV-based parsing system for Node, Link, and Prefix descriptors and attributes
* added support for RFC 8571 traffic engineering performance metrics (TLVs 1114-1120)
* added support for RFC 9085 Segment Routing extensions (TLVs 1170-1172, 1174)
* added support for RFC 9294 Application-Specific Link Attributes (TLV 1122)
* created structured data model with helper methods for common attribute access
* maintains backward compatibility with non-breaking optional field additions
* add support for RFC 8654 Extended Messages
* updated message length validation to support extended messages up to 65535 bytes
* resolves parsing errors for large BGP messages (e.g., "invalid BGP message length 4834")
* implemented BGP Extended Message capability (capability code 6) for parsing and encoding
* added proper RFC 8654 validation constraints (OPEN and KEEPALIVE messages remain limited to 4096 bytes)
* added test cases for extended message length validation and capability parsing
* implemented comprehensive BGP capabilities support for all IANA-defined capability codes with RFC support
* added structured parsing and encoding for 7 major BGP capabilities (RFC2858, RFC2918, RFC4724, RFC6793, RFC7911, RFC8950, RFC9234)
* implemented `MultiprotocolExtensionsCapability` for AFI/SAFI advertisement per RFC2858
* implemented `RouteRefreshCapability` for dynamic route refresh support per RFC2918
* implemented `GracefulRestartCapability` with restart flags and per-AF forwarding state per RFC4724
* implemented `FourOctetAsCapability` for 4-byte AS number support per RFC6793
* implemented `AddPathCapability` with send/receive modes for multiple path advertisement per RFC7911
* implemented `BgpRoleCapability` with Provider/Customer/Peer/RouteServer roles per RFC9234
* added graceful fallback to raw bytes for unrecognized or parsing-failed capabilities
* added comprehensive test coverage with 26 test cases covering all implemented capabilities
* updated `CapabilityValue` enum with 7 new structured capability variants
* maintains backward compatibility while providing structured access to capability data
* added RFC 8950 support for IPv4 NLRI with IPv6 next-hops
* extended `Safi` enum with `MplsVpn` (128) and `MulticastVpn` (129) for VPN address families
* added `RouteDistinguisher` type for VPN next-hop parsing
* extended `NextHopAddress` enum with `VpnIpv6` and `VpnIpv6LinkLocal` variants
* updated `parse_mp_next_hop` to handle 24-byte and 48-byte VPN next-hops
* enables parsing of VPN-IPv4 routes with VPN-IPv6 next-hops per RFC 8950 Section 4
* added RFC 8950 Extended Next Hop capability parsing and encoding
* implemented `ExtendedNextHopCapability` for BGP OPEN message capability negotiation
* supports arbitrary AFI/SAFI combinations per RFC 8950 Section 3
* added structured capability parsing with fallback to raw bytes for compatibility
* enables BGP speakers to advertise ability to receive cross-protocol next-hops
* includes comprehensive validation and helper methods for capability querying
* added RFC 9069 validation warnings for BMP Local RIB peer types
* validates Local RIB peer header requirements including zero-filled peer address and 4-byte ASN encoding
* validates Local RIB peer up notifications for fabricated OPEN messages and VrTableName TLV presence
* validates Local RIB route monitoring messages for proper ASN encoding
* validation warnings logged when BMP messages do not conform to RFC 9069 specifications
#### Performance improvements
* optimized BytesMut buffer allocation patterns for better memory efficiency
* replaced `BytesMut::with_capacity() + resize()` with `BytesMut::zeroed()` for cleaner initialization
* added capacity pre-allocation in ASN encoding to avoid reallocations
* replaced unnecessary BytesMut allocations with direct slice references in MRT header parsing
* added capacity pre-allocation in MRT record encoding for optimal buffer sizing
* fixed non-canonical PartialOrd implementation for ASN type to follow Rust idioms
#### Iterator improvements
* added fallible iterator implementations for explicit error handling
* implemented `FallibleRecordIterator` that returns `Result<MrtRecord, ParserErrorWithBytes>`
* implemented `FallibleElemIterator` that returns `Result<BgpElem, ParserErrorWithBytes>`
* added `into_fallible_record_iter()` and `into_fallible_elem_iter()` methods on `BgpkitParser`
* allows users to handle parsing errors explicitly instead of having them silently skipped
* maintains full backward compatibility with existing error-skipping iterators
* reorganized iterator implementations into structured `iters` module with `default` and `fallible` submodules
* added raw MRT record iteration support for record-by-record processing (PR #239)
* added `RawRecordIterator` accessible via `into_raw_record_iter()` on `BgpkitParser`
* separated MRT record reading from parsing for clearer error handling and improved throughput
* moved `RawRecordIterator` into dedicated `iters::raw` module for better organization
* added raw record parsing to `scan_mrt` example
* added tests comparing `into_raw_record_iter()` with `record_iter()` behavior
* optimized duplicate BGP attribute detection using a fixed-size boolean array to track seen attributes (PR #239)
* added boundary test cases for BGP attribute types
### Bug fixes
* fixed TABLE_DUMP_V2 parsing to properly store path_id when AddPath is enabled
* previously path_id was read but discarded, now properly stored in `RibEntry`
* clarified in-bounds indexing for BGP attribute types when tracking seen attributes (PR #239)
* index attribute type as `u8` when indexing the seen-attributes array to ensure bounds correctness
* fixed BGP OPEN message optional parameter parsing to support multiple capabilities per parameter
* changed `ParamValue::Capability` to `ParamValue::Capacities(Vec<Capability>)` to properly handle RFC 5492 format
* previously parser only read the first capability in each optional parameter, ignoring subsequent capabilities
* now correctly parses all capabilities within each optional parameter
* updated encoding logic to write all capabilities in the vector
* fixed RFC 9072 Extended Optional Parameters Length validation
* corrected extended parameter format validation (must have non-zero opt_params_len)
* fixed capability length parsing to always use 1-byte length per RFC 5492, not variable length
* ensures proper RFC 9072 compliance for extended OPEN message format
* improved RFC 9069 validation for BMP Local RIB peer types
* fixed multi-protocol capability check to specifically validate MULTIPROTOCOL_EXTENSIONS capability presence
* previously checked for any capabilities, now correctly validates the required capability type
* added `CorruptedBgpMessage` error type for better BMP parsing error handling
* provides more specific error information when BGP messages within BMP are corrupted
### Maintenance
* updated dependencies
* updated crate documentation and README
* removed outdated documentation files
## v0.11.1 - 2025-06-06
### Bug fixes
* Fixed an issue where IPv6 NLRI next-hop addresses were not properly passed to `BgpElem` objects.
* The fix ensures that the `next_hop` value is extracted from either `NEXT_HOP` or `MP_REACHABLE_NLRI` BGP
attribute, and is correctly set in the `BgpElem` object.
* Fixes issue [#211](https://github.com/bgpkit/bgpkit-parser/issues/211)
* Thanks [m-appel](https://github.com/m-appel) for reporting this issue!
### Maintenance
* Apply `cargo clippy` lints to the codebase
* Add more tests to improve code coverage
## v0.11.0 - 2025-02-26
### Breaking changes
* removing string format prefix like `lg:` or `ecv6` for large and extended communities
* users who work with community value strings will have a unified experience for all community values
* users can still use SDK to match and check different types of community values
### Highlights
* storing AS path filter regex object for reuse
* this will improve filter performance
* allow filter messages by community values
* by converting community values to string and do string comparison
* add `local` flag to allow local-only processing
* this removes dependencies like `reqwest`
* support converting singleton AsSet to Vec<u32>
* when calling `to_u32_vec_opt` on AS path object, singleton AsSet will be treated as single ASN
### Bug fixes
* fixed a bug where RIS-live withdrawal messages were not properly parsed
### Documentation
* add new RIS-Live async example
### Maintenance
* update dependencies
* add `.env` to gitignore
* remote unnecessary life-time annotations
## v0.10.11 - 2024-10-27
### Highlights
* Improved RIS Live message types and handling
* clean up dependencies
* `models` feature is removed, and all dependencies are now required dependencies for the crate
* `models` module no-longer requires dependencies introduced by parser, like `bytes` for encoding
* decouple `oneio` from `parser` feature
* `oneio` is no-longer a required dependency for the parser
* users can now use `parser` feature without `oneio` (with `--no-default-features` specified)
* to create a new parser, one needs to user `BgpkitParser::from_reader` function instead of `BgpkitParser::new`
* downstream libraries that only utilize parser code (such as RIS Live parsing) no-longer have to depend on oneio
* improve RouteViews Kafka example by allowing wildcard topic subscription
### Bug fixes
* fixed an issue where when merging `AS_PATH` and `AS4_PATH` segments, the parser incorrectly uses `AS_PATH` segment
content
* this issue may manifest as `AS_TRANS` (`AS23456`) appearing in the AS path while the correct 32-bit ASN has been
sent in `AS4_PATH`
## v0.10.11-beta.1 - 2024-10-16
### Highlights
* Improved RIS Live message types and handling
* clean up dependencies
* `models` feature is removed, and all dependencies are now required dependencies for the crate
* `models` module no-longer requires dependencies introduced by parser, like `bytes` for encoding
* decouple `oneio` from `parser` feature
* `oneio` is no-longer a required dependency for the parser
* users can now use `parser` feature without `oneio` (with `--no-default-features` specified)
* to create a new parser, one needs to user `BgpkitParser::from_reader` function instead of `BgpkitParser::new`
* downstream libraries that only utilize parser code (such as RIS Live parsing) no-longer have to depend on oneio
## v0.10.10 - 2024-08-05
### Highlights
* update `oneio` to v0.17.0
* now users can set env var `ONEIO_ACCEPT_INVALID_CERTS=true` to disable certificate validation, useful in some
environment where users do not manage certificates
## v0.10.9 - 2024-04-12
### BMP messages SDK improvements
* expose all pub structs and enums for BMP messages
* this allows users to access struct definitions and operate on them directly
* added `Copy` to `BmpMsgType`, `BmpPeerType` and `BmpPerPeerHeader`, `PerPeerFlags`, `BmpPeerType`
* implemented `Default`, `PartialEq`, `Eq` and `Hash` for `BmpPerPeerHeader`
* this allows users and compare and hash `BmpPerPeerHeader` structs
* also implemented `.strip_timestamp()` to remove the timestamp from the `BmpPerPeerHeader` struct for cases where
the timestamp is not needed
* rename `MessageBody` to `BmpMessageBody`
* derive `Clone`, `PartialEq` to `BmpMessage` and `MessageBody`
* added serialization/deserialization support for `BmpMessage` and `BmpMessageBody`
## v0.10.8 - 2024-04-05
### Highlights
* improve support for more BMP data types and better error
handling ([#163](https://github.com/bgpkit/bgpkit-parser/pull/163))
* added explicit enum `PeerDownReason`, `TerminationReason`, `PeerUpTlvType` instead of saving them as integers
* added support for AFI-SAFI gauge for `StatisticsReport` message
* this fixes issue [#162](https://github.com/bgpkit/bgpkit-parser/pull/162)
* added `UnknownTlvType` and `UnknownTlvValue` errors for parsing BMP TLV records
* added `Clone` and `PartialEq` derives to most of the BMP message structs
## v0.10.7 - 2024-03-30
### Highlights
* improve end-of-RIB marker detection ([#161](https://github.com/bgpkit/bgpkit-parser/pull/161))
## v0.10.6 - 2024-03-30
### Bug fix
* fixed an code panic issue where malformed RIB dump entry with non-existing peer ID causes a panic
* also removed a number of unwraps in the code to handle errors more gracefully
* see issue [#157](https://github.com/bgpkit/bgpkit-parser/issues/158) for details
## v0.10.5 - 2024-03-26
### Highlights
* by default handles only `gzip` and `bzip2` files
* to support `xz` and `lz` files, use the optional feature `xz` and `lz`
## v0.10.4 - 2024-03-20
### Hot fix
* update `oneio` to `v0.16.4`
* add `http2` and `charset` feature flag to `reqwest`
## v0.10.3 - 2024-03-20
### Highlights
* fixed an panic issue when sometimes merging AS path segments of 4-byte ASN path and 2-byte ASN path
* see issue [#156](https://github.com/bgpkit/bgpkit-parser/issues/156) for details
* update `oneio` to `v0.16.3`
* gzip decompression depends on `flate2`'s `rust-backend` feature instead of `zlib-ng` which requires `cmake` to
build
## v0.10.2 - 2024-03-06
### Highlights
* added new `ip_version` filter type with values of `ipv4` or `ipv6`
* library users can use this filter to filter BGP messages by IP version
* CLI users can specify `-4` or `-6` to filter BGP messages by IP version
* add new dependency security checkups using `cargo audit`
* all new releases will need to pass `cargo audit` checks before being published
* weekly `cargo audit` checks added to the CI pipeline
## v0.10.1 - 2024-02-23
### Highlights
* updating `oneio` to `v0.16.2`
* switching to `flate2` with `zlib-ng` for handling `gzip` files, which is significantly faster than the default
pure-Rust implementation
## v0.10.0 - 2024-02-12
Version 0.10.0 is a major release with a lot of changes and improvements.
### Highlights
#### MRT Encoding
`bgpkit-parser` now supports encoding MRT messages. The following MRT message types are supported:
- TableDumpV1
- TableDumpV2
- BGP4MP
It also supports encoding BMP messages into MRT files.
Example of writing BgpElems into a file RIB dump file:
```rust
let mut encoder = bgpkit_parser::encoder::MrtRibEncoder::new();
for elem in parser {
encoder.process_elem( & elem);
}
let mut writer = oneio::get_writer("filtered.rib.gz").unwrap();
writer.write_all(encoder.export_bytes().as_ref()).unwrap();
drop(writer);
```
Another example of writing `BgpElem` to BGP updates bytes:
```rust
let mut encoder = bgpkit_parser::encoder::MrtUpdatesEncoder::new();
let mut elem = BgpElem::default ();
elem.peer_ip = IpAddr::V4("10.0.0.1".parse().unwrap());
elem.peer_asn = Asn::from(65000);
elem.prefix.prefix = "10.250.0.0/24".parse().unwrap();
encoder.process_elem( & elem);
elem.prefix.prefix = "10.251.0.0/24".parse().unwrap();
encoder.process_elem( & elem);
let bytes = encoder.export_bytes();
let mut cursor = Cursor::new(bytes.clone());
while cursor.has_remaining() {
let parsed = parse_mrt_record( & mut cursor).unwrap();
dbg ! ( & parsed);
}
```
See `encoder` module for more details.
#### Better developer experiences
- added several utility functions to `BgpElem`
- `.is_announcement()`: check if the BGP element is an announcement
- `.get_as_path_opt()`: get the AS path if it exists and no AS set or confederated segments
- `.get_origin_asn_opt()`: get the origin ASN if it exists
- full `serde` serialization support
- add `BgpElem` to PSV (pipe-separated values) conversion
- improved time-related filters parsing
- `ts_start` `start_ts` `ts_end` `end_ts` are all supported
- many quality of life improvements by [@jmeggitt](https://github.com/jmeggitt)
- https://github.com/bgpkit/bgpkit-parser/pull/122
- https://github.com/bgpkit/bgpkit-parser/pull/123
#### Improved testing coverage
- `bgpkit-parser` code test coverage is now at 92%.
- codecov.io coverage report is available at https://app.codecov.io/gh/bgpkit/bgpkit-parser
#### TLS backend choice
- by default, `bgpkit-parser` now uses `rustls` as the default TLS backend
- `openssl` is still supported, but it is no longer the default
- `openssl` support can be enabled by using the `native-tls` feature flag and set default features to `false`
### Added RFCs support
- [`RFC 4724: Graceful Restart Mechanism for BGP`][rfc4724]
- [`RFC 8671 Support for Adj-RIB-Out in the BGP Monitoring Protocol (BMP)`][rfc8671]
- [`RFC 9069: Support for Local RIB in the BGP Monitoring Protocol (BMP)`][rfc9069]
- the supported RFCs list is documented at https://github.com/bgpkit/bgpkit-parser?tab=readme-ov-file#rfcs-support
[rfc4724]: https://www.rfc-editor.org/rfc/rfc4724
[rfc8671]: https://www.rfc-editor.org/rfc/rfc8671
[rfc9069]: https://www.rfc-editor.org/rfc/rfc9069
### Fixes
- fixed a bug where when multiple `AsSequences` are present, only the first one is parsed
- issue: https://github.com/bgpkit/bgpkit-parser/issues/140
- fixed a bug where the parser panics when messages are truncated
- https://github.com/bgpkit/bgpkit-parser/issues/149
### Other changes
- Move pybgpkit to its own repository at https://github.com/bgpkit/pybgpkit
- CLI build feature changed from `build-binary` to `cli`
- add more ways to install compiled `bgpkit-parser` CLI
- homebrew on macOS: `brew install bgpkit/tap/bgpkit-parser`
- other platforms: `cargo binstall bgpkit-parser`
## v0.10.0-beta.3 - 2024-02-08
### Highlights
`Bytes::split_to` will panic if not enough bytes available.
We added multiple safety checks to make sure enough bytes are available before calling `.split_to()` function.
If not enough bytes available, it will send out a `TruncatedMsg` error.
The current iterator will catch the error and skip the remainder of the message.
### Breaking changes
- remove `IoNotEnoughBytes`, and use `TruncatedMsg` when not enough bytes available to read
### Other changes
- bump `bytes` crate version to `1.5.0`
## v0.10.0-beta.2 - 2024-01-29
### Highlights
- switch to `rustls` as default TLS backend and remove unnecessary build dependencies and feature flags
- updated `oneio` to v0.16.0
- remove `openssl` and `vendored-openssl` dependency and feature flag for building CLI binary
- remove `ureq` dev-dependency
### Release process changes
- added `cargo binstall` support
- added SHA256 checksum to corresponding release binary files
## v0.10.0-beta.1 - 2024-01-03
* add TableDumpV2 support: https://github.com/bgpkit/bgpkit-parser/pull/146
* increase code test coverage to 92%: https://github.com/bgpkit/bgpkit-parser/pull/147