Skip to main content

bgpkit_parser/models/mrt/
bgp4mp.rs

1//! MRT BGP4MP structs
2use crate::models::*;
3use num_enum::{IntoPrimitive, TryFromPrimitive};
4use std::net::IpAddr;
5
6/// BGP finite-state-machine states.
7///
8/// Values 1 through 6 are defined by RFC 6396. [`BgpState::Clearing`] and
9/// [`BgpState::Deleted`] are Quagga extensions found in historical MRT data.
10#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[repr(u16)]
13pub enum BgpState {
14    Idle = 1,
15    Connect = 2,
16    Active = 3,
17    OpenSent = 4,
18    OpenConfirm = 5,
19    Established = 6,
20    Clearing = 7,
21    Deleted = 8,
22}
23
24/// BGP4MP message types.
25#[derive(Debug, Clone, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub enum Bgp4MpEnum {
28    StateChange(Bgp4MpStateChange),
29    Message(Bgp4MpMessage),
30}
31
32impl Bgp4MpEnum {
33    pub const fn msg_type(&self) -> Bgp4MpType {
34        match self {
35            Bgp4MpEnum::StateChange(x) => x.msg_type,
36            Bgp4MpEnum::Message(x) => x.msg_type,
37        }
38    }
39}
40
41/// BGP4MP message subtypes.
42#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Eq, Hash)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44#[repr(u16)]
45pub enum Bgp4MpType {
46    StateChange = 0,
47    Message = 1,
48    MessageAs4 = 4,
49    StateChangeAs4 = 5,
50    MessageLocal = 6,
51    MessageAs4Local = 7,
52    MessageAddpath = 8,
53    MessageAs4Addpath = 9,
54    MessageLocalAddpath = 10,
55    MessageLocalAs4Addpath = 11,
56}
57
58/// BGP4MP state change message.
59#[derive(Debug, Clone, PartialEq, Eq)]
60#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
61pub struct Bgp4MpStateChange {
62    pub msg_type: Bgp4MpType,
63    pub peer_asn: Asn,
64    pub local_asn: Asn,
65    pub interface_index: u16,
66    pub peer_ip: IpAddr,
67    pub local_addr: IpAddr,
68    pub old_state: BgpState,
69    pub new_state: BgpState,
70}
71
72/// BGP4MP message.
73#[derive(Debug, Clone, PartialEq, Eq)]
74#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
75pub struct Bgp4MpMessage {
76    pub msg_type: Bgp4MpType,
77    pub peer_asn: Asn,
78    pub local_asn: Asn,
79    pub interface_index: u16,
80    pub peer_ip: IpAddr,
81    pub local_ip: IpAddr,
82    pub bgp_message: BgpMessage,
83}
84
85impl Bgp4MpMessage {
86    pub const fn is_local(&self) -> bool {
87        matches!(
88            self.msg_type,
89            Bgp4MpType::MessageLocal
90                | Bgp4MpType::MessageAs4Local
91                | Bgp4MpType::MessageLocalAddpath
92                | Bgp4MpType::MessageLocalAs4Addpath
93        )
94    }
95}
96
97pub const fn address_family(ip: &IpAddr) -> u16 {
98    match ip {
99        IpAddr::V4(_) => 1,
100        IpAddr::V6(_) => 2,
101    }
102}
103
104#[cfg(test)]
105mod tests {
106    use super::*;
107    use std::str::FromStr;
108
109    #[test]
110    fn test_msg_type() {
111        let state_change = Bgp4MpEnum::StateChange(Bgp4MpStateChange {
112            msg_type: Bgp4MpType::StateChange,
113            peer_asn: Asn::new_32bit(0),
114            local_asn: Asn::new_32bit(0),
115            interface_index: 1,
116            peer_ip: IpAddr::from_str("10.0.0.0").unwrap(),
117            local_addr: IpAddr::from_str("10.0.0.1").unwrap(),
118            old_state: BgpState::Idle,
119            new_state: BgpState::Connect,
120        });
121        assert_eq!(state_change.msg_type(), Bgp4MpType::StateChange);
122
123        let message = Bgp4MpEnum::Message(Bgp4MpMessage {
124            msg_type: Bgp4MpType::Message,
125            peer_asn: Asn::new_32bit(0),
126            local_asn: Asn::new_32bit(0),
127            interface_index: 1,
128            peer_ip: IpAddr::from_str("10.0.0.0").unwrap(),
129            local_ip: IpAddr::from_str("10.0.0.1").unwrap(),
130            bgp_message: BgpMessage::Update(Default::default()),
131        });
132        assert_eq!(message.msg_type(), Bgp4MpType::Message);
133    }
134
135    #[test]
136    fn test_is_local() {
137        let mut message = Bgp4MpMessage {
138            msg_type: Bgp4MpType::Message,
139            peer_asn: Asn::new_32bit(0),
140            local_asn: Asn::new_32bit(0),
141            interface_index: 1,
142            peer_ip: IpAddr::from_str("10.0.0.0").unwrap(),
143            local_ip: IpAddr::from_str("10.0.0.1").unwrap(),
144            bgp_message: BgpMessage::Update(Default::default()),
145        };
146        assert!(!message.is_local());
147
148        message.msg_type = Bgp4MpType::MessageLocal;
149        assert!(message.is_local());
150
151        message.msg_type = Bgp4MpType::MessageAs4Local;
152        assert!(message.is_local());
153
154        message.msg_type = Bgp4MpType::MessageLocalAddpath;
155        assert!(message.is_local());
156
157        message.msg_type = Bgp4MpType::MessageLocalAs4Addpath;
158        assert!(message.is_local());
159
160        message.msg_type = Bgp4MpType::MessageAs4;
161        assert!(!message.is_local());
162    }
163
164    #[test]
165    #[cfg(feature = "serde")]
166    fn test_serialization() {
167        let state_change = Bgp4MpEnum::StateChange(Bgp4MpStateChange {
168            msg_type: Bgp4MpType::StateChange,
169            peer_asn: Asn::new_32bit(0),
170            local_asn: Asn::new_32bit(0),
171            interface_index: 1,
172            peer_ip: IpAddr::from_str("10.0.0.0").unwrap(),
173            local_addr: IpAddr::from_str("10.0.0.1").unwrap(),
174            old_state: BgpState::Idle,
175            new_state: BgpState::Connect,
176        });
177        let serialized = serde_json::to_string(&state_change).unwrap();
178        let deserialized: Bgp4MpEnum = serde_json::from_str(&serialized).unwrap();
179        assert_eq!(deserialized, state_change);
180
181        let message = Bgp4MpEnum::Message(Bgp4MpMessage {
182            msg_type: Bgp4MpType::Message,
183            peer_asn: Asn::new_32bit(0),
184            local_asn: Asn::new_32bit(0),
185            interface_index: 1,
186            peer_ip: IpAddr::from_str("10.0.0.0").unwrap(),
187            local_ip: IpAddr::from_str("10.0.0.1").unwrap(),
188            bgp_message: BgpMessage::Update(Default::default()),
189        });
190        let serialized = serde_json::to_string(&message).unwrap();
191        let deserialized: Bgp4MpEnum = serde_json::from_str(&serialized).unwrap();
192        assert_eq!(deserialized, message);
193    }
194}