bgpkit_parser/models/bgp/
mod.rs

1//! BGP messages and relevant structs.
2
3pub mod attributes;
4pub mod capabilities;
5pub mod community;
6pub mod elem;
7pub mod error;
8pub mod role;
9
10pub use attributes::*;
11pub use community::*;
12pub use elem::*;
13pub use error::*;
14pub use role::*;
15
16use crate::models::network::*;
17use capabilities::BgpCapabilityType;
18use num_enum::{IntoPrimitive, TryFromPrimitive};
19use std::net::Ipv4Addr;
20
21pub type BgpIdentifier = Ipv4Addr;
22
23#[derive(Debug, TryFromPrimitive, IntoPrimitive, Copy, Clone, PartialEq, Hash)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25#[repr(u8)]
26pub enum BgpMessageType {
27    OPEN = 1,
28    UPDATE = 2,
29    NOTIFICATION = 3,
30    KEEPALIVE = 4,
31}
32
33// https://tools.ietf.org/html/rfc4271#section-4
34#[derive(Debug, Clone, PartialEq, Eq)]
35#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
36pub enum BgpMessage {
37    Open(BgpOpenMessage),
38    Update(BgpUpdateMessage),
39    Notification(BgpNotificationMessage),
40    KeepAlive,
41}
42
43impl BgpMessage {
44    pub const fn msg_type(&self) -> BgpMessageType {
45        match self {
46            BgpMessage::Open(_) => BgpMessageType::OPEN,
47            BgpMessage::Update(_) => BgpMessageType::UPDATE,
48            BgpMessage::Notification(_) => BgpMessageType::NOTIFICATION,
49            BgpMessage::KeepAlive => BgpMessageType::KEEPALIVE,
50        }
51    }
52}
53
54/// BGP Open Message
55///
56/// ```text
57///  0                   1                   2                   3
58///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
59///  +-+-+-+-+-+-+-+-+
60///  |    Version    |
61///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62///  |     My Autonomous System      |
63///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64///  |           Hold Time           |
65///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66///  |                         BGP Identifier                        |
67///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68///  | Opt Parm Len  |
69///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70///  |                                                               |
71///  |             Optional Parameters (variable)                    |
72///  |                                                               |
73///  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
74/// ```
75#[derive(Debug, Clone, PartialEq, Eq)]
76#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
77pub struct BgpOpenMessage {
78    pub version: u8,
79    pub asn: Asn,
80    pub hold_time: u16,
81    pub sender_ip: Ipv4Addr,
82    pub extended_length: bool,
83    pub opt_params: Vec<OptParam>,
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88pub struct OptParam {
89    pub param_type: u8,
90    pub param_len: u16,
91    pub param_value: ParamValue,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
96pub enum ParamValue {
97    Raw(Vec<u8>),
98    Capability(Capability),
99}
100
101/// BGP Capability.
102///
103/// - RFC3392: <https://datatracker.ietf.org/doc/html/rfc3392>
104/// - Capability codes: <https://www.iana.org/assignments/capability-codes/capability-codes.xhtml#capability-codes-2>
105#[derive(Debug, Clone, PartialEq, Eq)]
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107pub struct Capability {
108    pub ty: BgpCapabilityType,
109    pub value: Vec<u8>,
110}
111
112#[derive(Debug, Clone, PartialEq, Eq, Default)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub struct BgpUpdateMessage {
115    pub withdrawn_prefixes: Vec<NetworkPrefix>,
116    pub attributes: Attributes,
117    pub announced_prefixes: Vec<NetworkPrefix>,
118}
119
120#[derive(Debug, Clone, PartialEq, Eq)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
122pub struct BgpNotificationMessage {
123    pub error: BgpError,
124    pub data: Vec<u8>,
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130
131    #[test]
132    fn test_message_type() {
133        let open = BgpMessage::Open(BgpOpenMessage {
134            version: 4,
135            asn: Asn::new_32bit(1),
136            hold_time: 180,
137            sender_ip: Ipv4Addr::new(192, 0, 2, 1),
138            extended_length: false,
139            opt_params: vec![],
140        });
141        assert_eq!(open.msg_type(), BgpMessageType::OPEN);
142
143        let update = BgpMessage::Update(BgpUpdateMessage::default());
144        assert_eq!(update.msg_type(), BgpMessageType::UPDATE);
145
146        let notification = BgpMessage::Notification(BgpNotificationMessage {
147            error: BgpError::Unknown(0, 0),
148            data: vec![],
149        });
150        assert_eq!(notification.msg_type(), BgpMessageType::NOTIFICATION);
151
152        let keepalive = BgpMessage::KeepAlive;
153        assert_eq!(keepalive.msg_type(), BgpMessageType::KEEPALIVE);
154    }
155
156    #[test]
157    #[cfg(feature = "serde")]
158    fn test_serde() {
159        let open = BgpMessage::Open(BgpOpenMessage {
160            version: 4,
161            asn: Asn::new_32bit(1),
162            hold_time: 180,
163            sender_ip: Ipv4Addr::new(192, 0, 2, 1),
164            extended_length: false,
165            opt_params: vec![],
166        });
167        let serialized = serde_json::to_string(&open).unwrap();
168        let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
169        assert_eq!(open, deserialized);
170
171        let update = BgpMessage::Update(BgpUpdateMessage::default());
172        let serialized = serde_json::to_string(&update).unwrap();
173        let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
174        assert_eq!(update, deserialized);
175
176        let notification = BgpMessage::Notification(BgpNotificationMessage {
177            error: BgpError::Unknown(0, 0),
178            data: vec![],
179        });
180        let serialized = serde_json::to_string(&notification).unwrap();
181        let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
182        assert_eq!(notification, deserialized);
183
184        let keepalive = BgpMessage::KeepAlive;
185        let serialized = serde_json::to_string(&keepalive).unwrap();
186        let deserialized: BgpMessage = serde_json::from_str(&serialized).unwrap();
187        assert_eq!(keepalive, deserialized);
188    }
189}