bgpkit_parser/parser/mrt/messages/
bgp4mp.rs

1use crate::error::ParserError;
2use crate::models::*;
3use crate::parser::bgp::messages::parse_bgp_message;
4use crate::parser::{encode_asn, encode_ipaddr, ReadUtils};
5use bytes::{Buf, BufMut, Bytes, BytesMut};
6use std::convert::TryFrom;
7
8/// Parse MRT BGP4MP type
9///
10/// RFC: <https://www.rfc-editor.org/rfc/rfc6396#section-4.4>
11///
12pub fn parse_bgp4mp(sub_type: u16, input: Bytes) -> Result<Bgp4MpEnum, ParserError> {
13    let bgp4mp_type: Bgp4MpType = Bgp4MpType::try_from(sub_type)?;
14    let msg: Bgp4MpEnum = match bgp4mp_type {
15        Bgp4MpType::StateChange => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
16            input,
17            AsnLength::Bits16,
18            &bgp4mp_type,
19        )?),
20        Bgp4MpType::StateChangeAs4 => Bgp4MpEnum::StateChange(parse_bgp4mp_state_change(
21            input,
22            AsnLength::Bits32,
23            &bgp4mp_type,
24        )?),
25        Bgp4MpType::Message | Bgp4MpType::MessageLocal => Bgp4MpEnum::Message(
26            parse_bgp4mp_message(input, false, AsnLength::Bits16, &bgp4mp_type)?,
27        ),
28        Bgp4MpType::MessageAs4 | Bgp4MpType::MessageAs4Local => Bgp4MpEnum::Message(
29            parse_bgp4mp_message(input, false, AsnLength::Bits32, &bgp4mp_type)?,
30        ),
31        Bgp4MpType::MessageAddpath | Bgp4MpType::MessageLocalAddpath => Bgp4MpEnum::Message(
32            parse_bgp4mp_message(input, true, AsnLength::Bits16, &bgp4mp_type)?,
33        ),
34        Bgp4MpType::MessageAs4Addpath | Bgp4MpType::MessageLocalAs4Addpath => Bgp4MpEnum::Message(
35            parse_bgp4mp_message(input, true, AsnLength::Bits32, &bgp4mp_type)?,
36        ),
37    };
38
39    Ok(msg)
40}
41
42fn total_should_read(afi: &Afi, asn_len: &AsnLength, total_size: usize) -> usize {
43    let ip_size = match afi {
44        Afi::Ipv4 => 4 * 2,
45        Afi::Ipv6 => 16 * 2,
46        Afi::LinkState => 4 * 2, // Link-State uses IPv4 format for compatibility
47    };
48    let asn_size = match asn_len {
49        AsnLength::Bits16 => 2 * 2,
50        AsnLength::Bits32 => 2 * 4,
51    };
52    total_size - asn_size - 2 - 2 - ip_size
53}
54/*
55   0                   1                   2                   3
56   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
57  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58  |         Peer AS Number        |        Local AS Number        |
59  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60  |        Interface Index        |        Address Family         |
61  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62  |                      Peer IP Address (variable)               |
63  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
64  |                      Local IP Address (variable)              |
65  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
66  |                    BGP Message... (variable)
67  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68*/
69pub fn parse_bgp4mp_message(
70    mut data: Bytes,
71    add_path: bool,
72    asn_len: AsnLength,
73    msg_type: &Bgp4MpType,
74) -> Result<Bgp4MpMessage, ParserError> {
75    let total_size = data.len();
76
77    let peer_asn: Asn = data.read_asn(asn_len)?;
78    let local_asn: Asn = data.read_asn(asn_len)?;
79    let interface_index: u16 = data.read_u16()?;
80    let afi: Afi = data.read_afi()?;
81    let peer_ip = data.read_address(&afi)?;
82    let local_ip = data.read_address(&afi)?;
83
84    let should_read = total_should_read(&afi, &asn_len, total_size);
85    if should_read != data.remaining() {
86        return Err(ParserError::TruncatedMsg(format!(
87            "truncated bgp4mp message: should read {} bytes, have {} bytes available",
88            should_read,
89            data.remaining()
90        )));
91    }
92    let bgp_message: BgpMessage = parse_bgp_message(&mut data, add_path, &asn_len)?;
93
94    Ok(Bgp4MpMessage {
95        msg_type: *msg_type,
96        peer_asn,
97        local_asn,
98        interface_index,
99        peer_ip,
100        local_ip,
101        bgp_message,
102    })
103}
104
105impl Bgp4MpMessage {
106    pub fn encode(&self, asn_len: AsnLength) -> Bytes {
107        let mut bytes = BytesMut::new();
108        bytes.extend(self.peer_asn.encode());
109        bytes.extend(self.local_asn.encode());
110        bytes.put_u16(self.interface_index);
111        bytes.put_u16(address_family(&self.peer_ip));
112        bytes.extend(encode_ipaddr(&self.peer_ip));
113        bytes.extend(encode_ipaddr(&self.local_ip));
114        bytes.extend(&self.bgp_message.encode(asn_len));
115        bytes.freeze()
116    }
117}
118
119/*
120   0                   1                   2                   3
121   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
122  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123  |         Peer AS Number        |        Local AS Number        |
124  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
125  |        Interface Index        |        Address Family         |
126  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
127  |                      Peer IP Address (variable)               |
128  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129  |                      Local IP Address (variable)              |
130  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131  |            Old State          |          New State            |
132  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133
134   0                   1                   2                   3
135   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
136  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137  |                         Peer AS Number                        |
138  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139  |                         Local AS Number                       |
140  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141  |        Interface Index        |        Address Family         |
142  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143  |                      Peer IP Address (variable)               |
144  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
145  |                      Local IP Address (variable)              |
146  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147  |            Old State          |          New State            |
148  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149*/
150pub fn parse_bgp4mp_state_change(
151    mut input: Bytes,
152    asn_len: AsnLength,
153    msg_type: &Bgp4MpType,
154) -> Result<Bgp4MpStateChange, ParserError> {
155    let peer_asn: Asn = input.read_asn(asn_len)?;
156    let local_asn: Asn = input.read_asn(asn_len)?;
157    let interface_index: u16 = input.read_u16()?;
158    let address_family: Afi = input.read_afi()?;
159    let peer_ip = input.read_address(&address_family)?;
160    let local_addr = input.read_address(&address_family)?;
161    let old_state = BgpState::try_from(input.read_u16()?)?;
162    let new_state = BgpState::try_from(input.read_u16()?)?;
163    Ok(Bgp4MpStateChange {
164        msg_type: *msg_type,
165        peer_asn,
166        local_asn,
167        interface_index,
168        peer_ip,
169        local_addr,
170        old_state,
171        new_state,
172    })
173}
174
175impl Bgp4MpStateChange {
176    pub fn encode(&self, asn_len: AsnLength) -> Bytes {
177        let mut bytes = BytesMut::new();
178        bytes.extend(encode_asn(&self.peer_asn, &asn_len));
179        bytes.extend(encode_asn(&self.local_asn, &asn_len));
180        bytes.put_u16(self.interface_index);
181        bytes.put_u16(address_family(&self.peer_ip));
182        bytes.extend(encode_ipaddr(&self.peer_ip));
183        bytes.extend(encode_ipaddr(&self.local_addr));
184        bytes.put_u16(self.old_state as u16);
185        bytes.put_u16(self.new_state as u16);
186        bytes.freeze()
187    }
188}