Skip to main content

bgp_rs/
notification.rs

1use std::fmt;
2use std::io::{Error, Read, Write};
3
4use byteorder::{ReadBytesExt, WriteBytesExt};
5
6use crate::*;
7
8/// Represents a BGP Notification message.
9#[derive(Clone, Debug)]
10pub struct Notification {
11    /// Major Error Code [RFC4271]
12    pub major_err_code: u8,
13    /// Minor Error Code [RFC4271]
14    pub minor_err_code: u8,
15    /// Notification data
16    pub data: Vec<u8>,
17}
18
19impl Notification {
20    /// Parse Notification message
21    /// Parses the error codes and checks for additional (optional) data
22    pub fn parse(header: &Header, stream: &mut impl Read) -> Result<Notification, Error> {
23        let major_err_code = stream.read_u8()?;
24        let minor_err_code = stream.read_u8()?;
25        let data = if header.length > 21 {
26            let remaining_length = header.length as usize - 21;
27            let mut data = vec![0; remaining_length as usize];
28            stream.read_exact(&mut data)?;
29            data
30        } else {
31            vec![]
32        };
33
34        Ok(Notification {
35            major_err_code,
36            minor_err_code,
37            data,
38        })
39    }
40
41    /// Encode message to bytes
42    pub fn encode(&self, buf: &mut impl Write) -> Result<(), Error> {
43        buf.write_u8(self.major_err_code)?;
44        buf.write_u8(self.minor_err_code)?;
45        buf.write_all(&self.data)
46    }
47
48    /// Major Error Code Description
49    pub fn major(&self) -> String {
50        match self.major_err_code {
51            1 => "Message Header Error".to_string(),
52            2 => "OPEN Message Error".to_string(),
53            3 => "UPDATE Message Error".to_string(),
54            4 => "Hold Timer Expired".to_string(),
55            5 => "Finite State Machine".to_string(),
56            6 => "Cease".to_string(),
57            _ => format!("Major Code {}", self.major_err_code),
58        }
59    }
60    /// Minor Error Code Description
61    pub fn minor(&self) -> String {
62        format!("{}", self.minor_err_code)
63    }
64
65    /// Included message (if present)
66    pub fn message(&self) -> Option<String> {
67        String::from_utf8(self.data.clone()).ok()
68    }
69}
70
71impl fmt::Display for Notification {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        write!(
74            f,
75            "{} / {} {}",
76            self.major(),
77            self.minor(),
78            self.message().unwrap_or_else(|| "".to_string())
79        )
80    }
81}
82
83#[test]
84fn test_notification_display() {
85    let notification = Notification {
86        major_err_code: 6,
87        minor_err_code: 3,
88        data: vec![],
89    };
90    assert_eq!(&notification.to_string(), "Cease / 3 ");
91    let notification = Notification {
92        major_err_code: 2,
93        minor_err_code: 1,
94        data: b"Unsupported Capability".to_vec(),
95    };
96    assert_eq!(
97        &notification.to_string(),
98        "OPEN Message Error / 1 Unsupported Capability"
99    );
100}