Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@ All notable changes to this project will be documented in this file.

### Code improvements

* 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 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
* added fallible iterator implementations for explicit error handling
* implemented `FallibleRecordIterator` that returns `Result<MrtRecord, ParserErrorWithBytes>`
* implemented `FallibleElemIterator` that returns `Result<BgpElem, ParserErrorWithBytes>`
Expand Down
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,12 @@ If you would like to see any specific RFC's support, please submit an issue on G
- [X] [RFC 9072](https://datatracker.ietf.org/doc/html/rfc9072): Extended Optional Parameters Length for BGP OPEN Message Updates
- [X] [RFC 9234](https://datatracker.ietf.org/doc/html/rfc9234): Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages

### Tunnel Encapsulation

- [X] [RFC 5640](https://datatracker.ietf.org/doc/html/rfc5640): Load-Balancing for Mesh Softwires
- [X] [RFC 8365](https://datatracker.ietf.org/doc/html/rfc8365): A Network Virtualization Overlay Solution Using Ethernet VPN (EVPN)
- [X] [RFC 9012](https://datatracker.ietf.org/doc/html/rfc9012): The BGP Tunnel Encapsulation Attribute

### MRT

- [X] [RFC 6396](https://datatracker.ietf.org/doc/html/rfc6396): Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format
Expand Down Expand Up @@ -408,6 +414,12 @@ We support normal communities, extended communities, and large communities.
- [ ] [RFC 8956](https://datatracker.ietf.org/doc/html/rfc8956) Dissemination of Flow Specification Rules for IPv6
- [ ] [RFC 9117](https://datatracker.ietf.org/doc/html/rfc9117) Revised Validation Procedure for BGP Flow Specifications Updates 8955

### Link-State
- [X] [RFC 7752](https://datatracker.ietf.org/doc/html/rfc7752): North-Bound Distribution of Link-State and Traffic Engineering (TE) Information Using BGP
- [X] [RFC 8571](https://datatracker.ietf.org/doc/html/rfc8571): BGP - Link State (BGP-LS) Advertisement of IGP Traffic Engineering Performance Metric Extensions
- [X] [RFC 9085](https://datatracker.ietf.org/doc/html/rfc9085): Border Gateway Protocol - Link State (BGP-LS) Extensions for Segment Routing
- [X] [RFC 9294](https://datatracker.ietf.org/doc/html/rfc9294): BGP-LS Advertisement of Application-Specific Link Attributes

## Built with ❤️ by BGPKIT Team

<a href="https://bgpkit.com"><img src="https://bgpkit.com/Original%20Logo%20Cropped.png" alt="https://bgpkit.com/favicon.ico" width="200"/></a>
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,12 @@ If you would like to see any specific RFC's support, please submit an issue on G
- [X] [RFC 9072](https://datatracker.ietf.org/doc/html/rfc9072): Extended Optional Parameters Length for BGP OPEN Message Updates
- [X] [RFC 9234](https://datatracker.ietf.org/doc/html/rfc9234): Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages

## Tunnel Encapsulation

- [X] [RFC 5640](https://datatracker.ietf.org/doc/html/rfc5640): Load-Balancing for Mesh Softwires
- [X] [RFC 8365](https://datatracker.ietf.org/doc/html/rfc8365): A Network Virtualization Overlay Solution Using Ethernet VPN (EVPN)
- [X] [RFC 9012](https://datatracker.ietf.org/doc/html/rfc9012): The BGP Tunnel Encapsulation Attribute

## MRT

- [X] [RFC 6396](https://datatracker.ietf.org/doc/html/rfc6396): Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format
Expand Down Expand Up @@ -400,6 +406,12 @@ We support normal communities, extended communities, and large communities.
- [ ] [RFC 8956](https://datatracker.ietf.org/doc/html/rfc8956) Dissemination of Flow Specification Rules for IPv6
- [ ] [RFC 9117](https://datatracker.ietf.org/doc/html/rfc9117) Revised Validation Procedure for BGP Flow Specifications Updates 8955

## Link-State
- [X] [RFC 7752](https://datatracker.ietf.org/doc/html/rfc7752): North-Bound Distribution of Link-State and Traffic Engineering (TE) Information Using BGP
- [X] [RFC 8571](https://datatracker.ietf.org/doc/html/rfc8571): BGP - Link State (BGP-LS) Advertisement of IGP Traffic Engineering Performance Metric Extensions
- [X] [RFC 9085](https://datatracker.ietf.org/doc/html/rfc9085): Border Gateway Protocol - Link State (BGP-LS) Extensions for Segment Routing
- [X] [RFC 9294](https://datatracker.ietf.org/doc/html/rfc9294): BGP-LS Advertisement of Application-Specific Link Attributes

# Built with ❤️ by BGPKIT Team

<a href="https://bgpkit.com"><img src="https://bgpkit.com/Original%20Logo%20Cropped.png" alt="https://bgpkit.com/favicon.ico" width="200"/></a>
Expand Down
7 changes: 7 additions & 0 deletions src/models/bgp/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,10 @@ pub enum AttributeValue {
Clusters(Vec<u32>),
MpReachNlri(Nlri),
MpUnreachNlri(Nlri),
/// BGP Link-State attribute - RFC 7752
LinkState(crate::models::bgp::linkstate::LinkStateAttribute),
/// BGP Tunnel Encapsulation attribute - RFC 9012
TunnelEncapsulation(crate::models::bgp::tunnel_encap::TunnelEncapAttribute),
Development(Vec<u8>),
Deprecated(AttrRaw),
Unknown(AttrRaw),
Expand Down Expand Up @@ -532,6 +536,8 @@ impl AttributeValue {
AttributeValue::Clusters(_) => AttrType::CLUSTER_LIST,
AttributeValue::MpReachNlri(_) => AttrType::MP_REACHABLE_NLRI,
AttributeValue::MpUnreachNlri(_) => AttrType::MP_UNREACHABLE_NLRI,
AttributeValue::LinkState(_) => AttrType::BGP_LS_ATTRIBUTE,
AttributeValue::TunnelEncapsulation(_) => AttrType::TUNNEL_ENCAPSULATION,
AttributeValue::Development(_) => AttrType::DEVELOPMENT,
AttributeValue::Deprecated(x) | AttributeValue::Unknown(x) => x.attr_type,
}
Expand All @@ -558,6 +564,7 @@ impl AttributeValue {
AttributeValue::Clusters(_) => Some(OptionalNonTransitive),
AttributeValue::MpReachNlri(_) => Some(OptionalNonTransitive),
AttributeValue::MpUnreachNlri(_) => Some(OptionalNonTransitive),
AttributeValue::LinkState(_) => Some(OptionalNonTransitive),
_ => None,
}
}
Expand Down
107 changes: 99 additions & 8 deletions src/models/bgp/attributes/nlri.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use crate::models::*;
use ipnet::IpNet;
use std::fmt::Debug;
use std::iter::Map;
use std::net::IpAddr;
use std::slice::Iter;
use std::vec::IntoIter;

/// Network Layer Reachability Information
#[derive(Debug, PartialEq, Clone, Eq)]
Expand All @@ -13,7 +10,10 @@ pub struct Nlri {
pub afi: Afi,
pub safi: Safi,
pub next_hop: Option<NextHopAddress>,
/// Traditional IP prefixes for unicast/multicast
pub prefixes: Vec<NetworkPrefix>,
/// Link-State NLRI data - RFC 7752
pub link_state_nlris: Option<Vec<crate::models::bgp::linkstate::LinkStateNlri>>,
}

impl Nlri {
Expand All @@ -27,6 +27,11 @@ impl Nlri {
matches!(self.afi, Afi::Ipv6)
}

/// Returns true if this NLRI refers to Link-State information.
pub const fn is_link_state(&self) -> bool {
matches!(self.afi, Afi::LinkState)
}

/// Returns true if this NLRI refers to reachable prefixes
pub const fn is_reachable(&self) -> bool {
self.next_hop.is_some()
Expand All @@ -38,7 +43,7 @@ impl Nlri {
pub const fn next_hop_addr(&self) -> IpAddr {
match self.next_hop {
Some(next_hop) => next_hop.addr(),
None => panic!("unreachable NLRI "),
None => panic!("unreachable NLRI"),
}
}

Expand All @@ -54,6 +59,7 @@ impl Nlri {
safi,
next_hop,
prefixes: vec![prefix],
link_state_nlris: None,
}
}

Expand All @@ -68,25 +74,62 @@ impl Nlri {
safi,
next_hop: None,
prefixes: vec![prefix],
link_state_nlris: None,
}
}

pub fn new_link_state_reachable(
next_hop: Option<IpAddr>,
safi: Safi,
nlri_list: Vec<crate::models::bgp::linkstate::LinkStateNlri>,
) -> Nlri {
let next_hop = next_hop.map(NextHopAddress::from);
Nlri {
afi: Afi::LinkState,
safi,
next_hop,
prefixes: Vec::new(),
link_state_nlris: Some(nlri_list),
}
}

pub fn new_link_state_unreachable(
safi: Safi,
nlri_list: Vec<crate::models::bgp::linkstate::LinkStateNlri>,
) -> Nlri {
Nlri {
afi: Afi::LinkState,
safi,
next_hop: None,
prefixes: Vec::new(),
link_state_nlris: Some(nlri_list),
}
}
}

impl IntoIterator for Nlri {
type Item = IpNet;
type IntoIter = Map<IntoIter<NetworkPrefix>, fn(NetworkPrefix) -> IpNet>;
type IntoIter = std::vec::IntoIter<IpNet>;

fn into_iter(self) -> Self::IntoIter {
self.prefixes.into_iter().map(|x| x.prefix)
self.prefixes
.into_iter()
.map(|x| x.prefix)
.collect::<Vec<_>>()
.into_iter()
}
}

impl<'a> IntoIterator for &'a Nlri {
type Item = &'a IpNet;
type IntoIter = Map<Iter<'a, NetworkPrefix>, fn(&NetworkPrefix) -> &IpNet>;
type IntoIter = std::vec::IntoIter<&'a IpNet>;

fn into_iter(self) -> Self::IntoIter {
self.prefixes.iter().map(|x| &x.prefix)
self.prefixes
.iter()
.map(|x| &x.prefix)
.collect::<Vec<_>>()
.into_iter()
}
}

Expand Down Expand Up @@ -201,4 +244,52 @@ mod tests {
assert_eq!(nlri.safi, Safi::Unicast);
assert_eq!(nlri.prefixes.len(), 1);
}

#[test]
fn nlri_link_state_creation() {
use crate::models::bgp::linkstate::{LinkStateNlri, NodeDescriptor, ProtocolId};

let node_desc = NodeDescriptor {
autonomous_system: Some(65001),
..Default::default()
};

let ls_nlri = LinkStateNlri::new_node_nlri(ProtocolId::Ospfv2, 123456, node_desc);
let nlri = Nlri::new_link_state_reachable(
Some("192.168.1.1".parse().unwrap()),
Safi::LinkState,
vec![ls_nlri],
);

assert!(nlri.is_link_state());
assert!(nlri.is_reachable());
assert_eq!(nlri.afi, Afi::LinkState);
assert_eq!(nlri.safi, Safi::LinkState);
}

#[test]
fn nlri_link_state_unreachable() {
use crate::models::bgp::linkstate::{LinkStateNlri, NodeDescriptor, ProtocolId};

let node_desc = NodeDescriptor::default();
let ls_nlri = LinkStateNlri::new_node_nlri(ProtocolId::Ospfv2, 123456, node_desc);
let nlri = Nlri::new_link_state_unreachable(Safi::LinkState, vec![ls_nlri]);

assert!(nlri.is_link_state());
assert!(!nlri.is_reachable());
assert_eq!(nlri.afi, Afi::LinkState);
assert_eq!(nlri.safi, Safi::LinkState);
}

#[test]
#[should_panic]
fn nlri_link_state_next_hop_addr_unreachable() {
use crate::models::bgp::linkstate::{LinkStateNlri, NodeDescriptor, ProtocolId};

let node_desc = NodeDescriptor::default();
let ls_nlri = LinkStateNlri::new_node_nlri(ProtocolId::Ospfv2, 123456, node_desc);
let nlri = Nlri::new_link_state_unreachable(Safi::LinkState, vec![ls_nlri]);

let _ = nlri.next_hop_addr();
}
}
8 changes: 4 additions & 4 deletions src/models/bgp/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,19 +905,19 @@ mod tests {

// Test parsing
let parsed = GracefulRestartCapability::parse(encoded).unwrap();
assert_eq!(parsed.restart_state, true);
assert!(parsed.restart_state);
assert_eq!(parsed.restart_time, 180);
assert_eq!(parsed.address_families.len(), 2);

// Check first AF
assert_eq!(parsed.address_families[0].afi, Afi::Ipv4);
assert_eq!(parsed.address_families[0].safi, Safi::Unicast);
assert_eq!(parsed.address_families[0].forwarding_state, true);
assert!(parsed.address_families[0].forwarding_state);

// Check second AF
assert_eq!(parsed.address_families[1].afi, Afi::Ipv6);
assert_eq!(parsed.address_families[1].safi, Safi::Unicast);
assert_eq!(parsed.address_families[1].forwarding_state, false);
assert!(!parsed.address_families[1].forwarding_state);
}

#[test]
Expand All @@ -927,7 +927,7 @@ mod tests {

let encoded = capability.encode();
let parsed = GracefulRestartCapability::parse(encoded).unwrap();
assert_eq!(parsed.restart_state, false);
assert!(!parsed.restart_state);
assert_eq!(parsed.restart_time, 300);
assert_eq!(parsed.address_families.len(), 0);
}
Expand Down
Loading