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