1use crate::{Error, Result};
2use bytes::{
3 Buf,
4 buf::BufExt,
5 BytesMut
6};
7use std::convert::{TryFrom, TryInto};
10use std::fmt;
11use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
12
13#[derive(Clone, Debug)]
16pub enum MessageData {
17 Unimplemented,
19 Initiation(Vec<InformationTlv>),
22 PeerUp((PeerHeader, PeerUp)),
25 PeerDown((PeerHeader, PeerDown)),
27 RouteMonitoring((PeerHeader, bgp_rs::Update)),
29}
30
31#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
33#[repr(u8)]
34pub enum MessageKind {
35 RouteMonitoring = 0,
37 StatisticsReport = 1,
39 PeerDown = 2,
41 PeerUp = 3,
43 Initiation = 4,
45 Termination = 5,
47 RouteMirroring = 6,
49
50 }
52
53impl TryFrom<u8> for MessageKind {
54 type Error = Error;
55
56 fn try_from(value: u8) -> Result<Self> {
57 match value {
58 0 => Ok(MessageKind::RouteMonitoring),
59 1 => Ok(MessageKind::StatisticsReport),
60 2 => Ok(MessageKind::PeerDown),
61 3 => Ok(MessageKind::PeerUp),
62 4 => Ok(MessageKind::Initiation),
63 5 => Ok(MessageKind::Termination),
64 6 => Ok(MessageKind::RouteMirroring),
65
66 v @ _ => Err(
67 Error::decode(&format!("invalid value for BMP Message Type: {}", v))
68 ),
69 }
70 }
71}
72
73impl fmt::Display for MessageKind {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 match self {
76 MessageKind::RouteMonitoring => write!(f, "route_monitoring"),
77 MessageKind::StatisticsReport => write!(f, "statistics_report"),
78 MessageKind::PeerUp => write!(f, "peer_up"),
79 MessageKind::PeerDown => write!(f, "peer_down"),
80 MessageKind::Initiation => write!(f, "initiation"),
81 MessageKind::Termination => write!(f, "termination"),
82 MessageKind::RouteMirroring => write!(f, "route_mirroring"),
83 }
84 }
85}
86
87#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
89#[repr(u8)]
90pub enum PeerType {
91 GlobalInstance = 0,
93 RdInstance = 1,
95 LocalInstance = 2,
97}
98
99impl TryFrom<u8> for PeerType {
100 type Error = Error;
101
102 fn try_from(value: u8) -> Result<Self> {
103 match value {
104 0 => Ok(PeerType::GlobalInstance),
105 1 => Ok(PeerType::RdInstance),
106 2 => Ok(PeerType::LocalInstance),
107
108 v @ _ => Err(
109 Error::decode(&format!("invalid value for BMP Peer Type: {}", v))
110 ),
111 }
112 }
113}
114
115impl fmt::Display for PeerType {
116 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
117 match self {
118 PeerType::GlobalInstance => write!(f, "global"),
119 PeerType::RdInstance => write!(f, "rd"),
120 PeerType::LocalInstance => write!(f, "local"),
121 }
122 }
123}
124
125#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
127#[allow(non_snake_case)]
128pub struct PeerFlags {
129 pub V: bool,
131 pub L: bool,
133 pub A: bool,
135 pub O: bool,
137}
138
139#[allow(non_snake_case)]
140impl From<u8> for PeerFlags {
141 fn from(value: u8) -> Self {
142 let V = value & 0b10000000 == 0b10000000;
143 let L = value & 0b01000000 == 0b01000000;
144 let A = value & 0b00100000 == 0b00100000;
145 let O = value & 0b00010000 == 0b00010000;
146
147 Self { V, L, A, O }
148 }
149}
150
151#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
153pub enum InformationType {
154 String,
156 SysDescr,
158 SysName,
160}
161
162impl TryFrom<u16> for InformationType {
163 type Error = Error;
164
165 fn try_from(value: u16) -> Result<Self> {
166 match value {
167 0 => Ok(InformationType::String),
168 1 => Ok(InformationType::SysDescr),
169 2 => Ok(InformationType::SysName),
170
171 v @ _ => Err(
172 Error::decode(&format!("invalid value for BMP Information Type: {}", v))
173 ),
174 }
175 }
176}
177
178impl fmt::Display for InformationType {
179 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
180 match self {
181 InformationType::String => write!(f, "string"),
182 InformationType::SysDescr => write!(f, "sys_descr"),
183 InformationType::SysName => write!(f, "sys_name"),
184 }
185 }
186}
187
188#[derive(Clone, Debug)]
190pub struct BmpMessage {
191 pub version: u8,
193 pub kind: MessageKind,
195 pub message: MessageData,
199}
200
201#[derive(Copy, Clone, Debug)]
207pub struct PeerHeader {
208 pub peer_type: PeerType,
210 pub peer_flags: PeerFlags,
212 pub peer_distinguisher: (u32, u32), pub peer_addr: IpAddr,
216 pub peer_asn: u32,
218 pub peer_bgp_id: Ipv4Addr,
220 pub timestamp: u32,
222 pub timestamp_ms: u32,
224}
225
226impl PeerHeader {
227 pub(super) fn decode(buf: &mut BytesMut) -> Result<Self> {
228 let peer_type: PeerType = buf.get_u8().try_into()?;
229 let peer_flags: PeerFlags = buf.get_u8().into();
230 let peer_distinguisher = (buf.get_u32(), buf.get_u32());
231
232 let peer_addr = match peer_flags.V {
233 false => {
235 buf.advance(12);
237 IpAddr::V4( Ipv4Addr::from(buf.get_u32()) )
238 },
239 true => {
241 IpAddr::V6( Ipv6Addr::from(buf.get_u128()) )
242 }
243 };
244
245 let peer_asn = match peer_flags.A {
246 true => {
248 buf.advance(2);
250 u32::from( buf.get_u16() )
251 },
252 false => buf.get_u32()
254 };
255
256 let peer_bgp_id = Ipv4Addr::from( buf.get_u32() );
257
258 let timestamp = buf.get_u32();
259 let timestamp_ms = buf.get_u32();
260
261 Ok(Self {
262 peer_type,
263 peer_flags,
264 peer_distinguisher,
265 peer_addr,
266 peer_asn,
267 peer_bgp_id,
268 timestamp,
269 timestamp_ms,
270 })
271 }
272}
273
274#[derive(Clone, Debug)]
278pub struct InformationTlv {
279 pub information_type: InformationType,
281 pub value: String,
283}
284
285impl InformationTlv {
286 pub(super) fn decode(kind: u16, buf: &mut BytesMut) -> Result<Self> {
287 let information_type = InformationType::try_from(kind)?;
288 let len = buf.get_u16() as usize;
289
290 let value = String::from_utf8((buf.bytes())[..len].to_vec()).unwrap();
291
292 Ok(Self { information_type, value })
293 }
294}
295
296#[derive(Clone, Debug)]
301pub struct PeerUp {
302 pub local_addr: IpAddr,
304 pub local_port: u16,
306 pub remote_port: u16,
308 pub sent_open: Option<bgp_rs::Open>,
310 pub recv_open: Option<bgp_rs::Open>,
312 pub information: Vec<InformationTlv>,
314}
315
316impl PeerUp {
317 pub(super) fn decode(peer_flags: &PeerFlags, buf: &mut BytesMut) -> Result<Self> {
318 let local_addr = match peer_flags.V {
319 false => {
321 buf.advance(12);
323 IpAddr::V4( Ipv4Addr::from(buf.get_u32()) )
324 },
325 true => {
327 IpAddr::V6( Ipv6Addr::from(buf.get_u128()) )
328 }
329 };
330
331 let local_port = buf.get_u16();
332 let remote_port = buf.get_u16();
333
334 if buf.remaining() == 0 {
337 return Ok(PeerUp {
338 local_addr,
339 local_port,
340 remote_port,
341 sent_open: None,
342 recv_open: None,
343 information: vec![]
344 });
345 }
346
347 let mut rdr = buf.reader();
348
349 let sent_hdr = bgp_rs::Header::parse(&mut rdr)?;
350 assert!(sent_hdr.record_type == 1);
351 let sent_open = Some(bgp_rs::Open::parse(&mut rdr)?);
352
353 let recv_hdr = bgp_rs::Header::parse(&mut rdr)?;
354 assert!(recv_hdr.record_type == 1);
355 let recv_open = Some(bgp_rs::Open::parse(&mut rdr)?);
356
357 let mut information = vec![];
358 while buf.remaining() > 0 {
359 let kind = buf.get_u16();
360 information.push( InformationTlv::decode(kind, buf)? );
361 }
362
363 Ok(PeerUp {
364 local_addr,
365 local_port,
366 remote_port,
367 sent_open,
368 recv_open,
369 information
370 })
371 }
372}
373
374#[derive(Clone, Debug)]
379#[non_exhaustive]
380pub enum PeerDown {
381 LocalShutdown(bgp_rs::Notification),
384 LocalTerminate(u16),
387 RemoteShutdown(bgp_rs::Notification),
389 RemoteTerminate,
392 ConfigurationChange,
395}
396
397impl PeerDown {
398 pub(super) fn decode(buf: &mut BytesMut) -> Result<Self> {
399 let reason = buf.get_u8();
400
401 match reason {
402 1 => {
403 let mut rdr = buf.reader();
404 let header = bgp_rs::Header::parse(&mut rdr)?;
405 let notification = bgp_rs::Notification::parse(&header, &mut rdr)?;
406
407 Ok(Self::LocalShutdown(notification))
408 },
410 2 => Ok(Self::LocalTerminate(buf.get_u16())),
411 3 => {
412 let mut rdr = buf.reader();
413 let header = bgp_rs::Header::parse(&mut rdr)?;
414 let notification = bgp_rs::Notification::parse(&header, &mut rdr)?;
415
416 Ok(Self::RemoteShutdown(notification))
417 },
419 4 => Ok(Self::RemoteTerminate),
420 5 => Ok(Self::ConfigurationChange),
421
422 v @ _ => Err(Error::decode(&format!("invalid value for BMP Peer Down reason: {}", v)))
423 }
424 }
425}