bgpkit_parser/parser/bmp/messages/
initiation_message.rs1use crate::parser::bmp::error::ParserBmpError;
2use crate::parser::ReadUtils;
3use bytes::{Buf, Bytes};
4use num_enum::{FromPrimitive, IntoPrimitive};
5
6#[derive(Debug, Clone, PartialEq)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct InitiationMessage {
9 pub tlvs: Vec<InitiationTlv>,
10}
11
12#[derive(Debug, PartialEq, Clone)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14pub struct InitiationTlv {
15 pub info_type: InitiationTlvType,
16 pub info_len: u16,
17 pub info: String,
18}
19
20#[derive(Debug, FromPrimitive, IntoPrimitive, PartialEq, Clone, Copy)]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30#[repr(u16)]
31pub enum InitiationTlvType {
32 String = 0,
33 SysDescr = 1,
34 SysName = 2,
35 VrTableName = 3,
37 AdminLabel = 4,
39 #[num_enum(catch_all)]
40 Unknown(u16) = 65535,
41}
42
43pub fn parse_initiation_message(data: &mut Bytes) -> Result<InitiationMessage, ParserBmpError> {
47 let mut tlvs = vec![];
48
49 while data.remaining() > 4 {
50 let info_type = InitiationTlvType::from(data.read_u16()?);
51 let info_len = data.read_u16()?;
52 if data.remaining() < info_len as usize {
53 break;
55 }
56 let info = data.read_n_bytes_to_string(info_len as usize)?;
57 tlvs.push(InitiationTlv {
58 info_type,
59 info_len,
60 info,
61 });
62 }
63
64 Ok(InitiationMessage { tlvs })
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use bytes::{BufMut, BytesMut};
71
72 #[test]
73 fn test_parse_initiation_message() {
74 let mut buffer = BytesMut::new();
75 buffer.put_u16(1); buffer.put_u16(5); buffer.put_slice(b"Test1"); let mut bytes = buffer.freeze();
80
81 match parse_initiation_message(&mut bytes) {
82 Ok(initiation_message) => {
83 for tlv in initiation_message.tlvs {
84 assert_eq!(tlv.info_type, InitiationTlvType::SysDescr);
85 assert_eq!(tlv.info_len, 5);
86 assert_eq!(tlv.info, "Test1".to_string());
87 }
88 }
89 Err(_) => panic!("Failed to parse initiation message"),
90 }
91 }
92
93 #[test]
94 fn test_parse_unknown_initiation_tlv() {
95 let mut buffer = BytesMut::new();
96 buffer.put_u16(1); buffer.put_u16(4);
99 buffer.put_slice(b"Test");
100 buffer.put_u16(255);
102 buffer.put_u16(3);
103 buffer.put_slice(b"Foo");
104
105 let mut bytes = buffer.freeze();
106 let result = parse_initiation_message(&mut bytes).unwrap();
107
108 assert_eq!(result.tlvs.len(), 2);
109 assert_eq!(result.tlvs[0].info_type, InitiationTlvType::SysDescr);
110 assert_eq!(result.tlvs[0].info, "Test");
111 assert_eq!(result.tlvs[1].info_type, InitiationTlvType::Unknown(255));
112 assert_eq!(result.tlvs[1].info_len, 3);
113 assert_eq!(result.tlvs[1].info, "Foo");
114 }
115
116 #[test]
117 fn test_debug() {
118 let initiation_message = InitiationMessage {
119 tlvs: vec![InitiationTlv {
120 info_type: InitiationTlvType::SysDescr,
121 info_len: 5,
122 info: "Test1".to_string(),
123 }],
124 };
125 assert_eq!(
126 format!("{initiation_message:?}"),
127 "InitiationMessage { tlvs: [InitiationTlv { info_type: SysDescr, info_len: 5, info: \"Test1\" }] }"
128 );
129 }
130}