routes/bmp/
encode.rs

1use std::convert::TryFrom;
2use std::{net::IpAddr, ops::Deref, str::FromStr};
3
4use bytes::{BufMut, Bytes, BytesMut};
5use chrono::Utc;
6use routecore::addr::Prefix;
7use routecore::asn::Asn;
8use routecore::bgp::aspath::HopPath;
9use routecore::bgp::communities::Community;
10use routecore::bgp::types::{
11    NextHop, OriginType, PathAttributeType, Afi, Safi,
12};
13use routecore::bmp::message::{
14    InformationTlvType, MessageType, PeerType, TerminationInformation,
15};
16
17pub fn mk_initiation_msg(sys_name: &str, sys_descr: &str) -> Bytes {
18    let mut buf = BytesMut::new();
19    push_bmp_common_header(&mut buf, MessageType::InitiationMessage);
20
21    // 4.3.  Initiation Message
22    //
23    // "The initiation message consists of the common BMP header followed by
24    //  two or more Information TLVs (Section 4.4) containing information
25    //  about the monitored router.  The sysDescr and sysName Information
26    //  TLVs MUST be sent, any others are optional.  The string TLV MAY be
27    //  included multiple times."
28    //
29    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.3
30
31    // 4.4.  Information TLV
32    //
33    //  0                   1                   2                   3
34    //  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
35    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36    // |          Information Type     |       Information Length      |
37    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38    // |                 Information (variable)                        |
39    // ~                                                               ~
40    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41    //
42    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.4
43
44    push_bmp_information_tlv(
45        &mut buf,
46        InformationTlvType::SysName,
47        sys_name.as_bytes(),
48    );
49    push_bmp_information_tlv(
50        &mut buf,
51        InformationTlvType::SysDesc,
52        sys_descr.as_bytes(),
53    );
54
55    finalize_bmp_msg_len(&mut buf);
56    buf.freeze()
57}
58
59// Returns the generated bytes and a, possibly empty, set of warning messages.
60#[allow(clippy::too_many_arguments)]
61#[allow(clippy::vec_init_then_push)]
62pub fn mk_peer_up_notification_msg(
63    per_peer_header: &PerPeerHeader,
64    local_address: IpAddr,
65    local_port: u16,
66    remote_port: u16,
67    sent_open_asn: u16,
68    received_open_asn: u16,
69    sent_bgp_identifier: u32,
70    received_bgp_identifier: u32,
71    information_tlvs: Vec<(InformationTlvType, String)>,
72    eor_capable: bool,
73) -> (Bytes, Vec<String>) {
74    let mut buf = BytesMut::new();
75    push_bmp_common_header(&mut buf, MessageType::PeerUpNotification);
76    let warnings = push_bmp_per_peer_header(&mut buf, per_peer_header);
77
78    // 4.10.  Peer Up Notification
79    //
80    //  0                   1                   2                   3
81    //  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
82    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83    // |                 Local Address (16 bytes)                      |
84    // ~                                                               ~
85    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86    // |         Local Port            |        Remote Port            |
87    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88    // |                    Sent OPEN Message                          |
89    // ~                                                               ~
90    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91    // |                  Received OPEN Message                        |
92    // ~                                                               ~
93    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94    // |                 Information (variable)                        |
95    // ~                                                               ~
96    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97    //
98    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.10
99
100    match local_address {
101        IpAddr::V4(addr) => {
102            assert!(per_peer_header.is_ipv4());
103            buf.resize(buf.len() + 12, 0u8);
104            buf.extend_from_slice(&addr.octets());
105        }
106        IpAddr::V6(addr) => {
107            assert!(per_peer_header.is_ipv6());
108            buf.extend_from_slice(&addr.octets());
109        }
110    }
111
112    buf.extend_from_slice(&local_port.to_be_bytes());
113    buf.extend_from_slice(&remote_port.to_be_bytes());
114
115    // 4.2.  OPEN Message Format
116    //
117    // After a TCP connection is established, the first message sent by each
118    // side is an OPEN message.  If the OPEN message is acceptable, a
119    // KEEPALIVE message confirming the OPEN is sent back.
120    //
121    // In addition to the fixed-size BGP header, the OPEN message contains
122    // the following fields:
123    //
124    //      0                   1                   2                   3
125    //      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
126    //     +-+-+-+-+-+-+-+-+
127    //     |    Version    |
128    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129    //     |     My Autonomous System      |
130    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131    //     |           Hold Time           |
132    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133    //     |                         BGP Identifier                        |
134    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135    //     | Opt Parm Len  |
136    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137    //     |                                                               |
138    //     |             Optional Parameters (variable)                    |
139    //     |                                                               |
140    //     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141    //
142    // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.2
143
144    // insert fake BGP open sent message
145    let mut bgp_msg_buf = BytesMut::new();
146    // Fixed size BGP header
147    bgp_msg_buf.resize(bgp_msg_buf.len() + 16, 0xFFu8); // marker
148    bgp_msg_buf.resize(bgp_msg_buf.len() + 2, 0); // placeholder length, to be replaced later
149    bgp_msg_buf.extend_from_slice(&1u8.to_be_bytes()); // 1 - OPEN
150    bgp_msg_buf.extend_from_slice(&4u8.to_be_bytes()); // BGP version 4
151
152    // Other fields
153    bgp_msg_buf.extend_from_slice(&sent_open_asn.to_be_bytes());
154    bgp_msg_buf.extend_from_slice(&0u16.to_be_bytes()); // 0 hold time - disables keep alive
155    bgp_msg_buf.extend_from_slice(&sent_bgp_identifier.to_be_bytes());
156    bgp_msg_buf.extend_from_slice(&0u8.to_be_bytes()); // 0 optional parameters
157
158    // Finalize BGP message
159    finalize_bgp_msg_len(&mut bgp_msg_buf);
160    buf.extend_from_slice(&bgp_msg_buf);
161
162    // insert fake BGP open received message
163    let mut bgp_msg_buf = BytesMut::new();
164    // Fixed size BGP header
165    bgp_msg_buf.resize(bgp_msg_buf.len() + 16, 0xFFu8); // marker
166    bgp_msg_buf.resize(bgp_msg_buf.len() + 2, 0); // placeholder length, to be replaced later
167    bgp_msg_buf.extend_from_slice(&1u8.to_be_bytes()); // 1 - OPEN
168    bgp_msg_buf.extend_from_slice(&4u8.to_be_bytes()); // BGP version 4
169
170    // Other fields
171    bgp_msg_buf.extend_from_slice(&received_open_asn.to_be_bytes());
172    bgp_msg_buf.extend_from_slice(&0u16.to_be_bytes()); // 0 hold time - disables keep alive
173    bgp_msg_buf.extend_from_slice(&received_bgp_identifier.to_be_bytes());
174
175    if !eor_capable {
176        bgp_msg_buf.extend_from_slice(&0u8.to_be_bytes()); // 0 optional parameter bytes
177    } else {
178        // A peer capable of sending the special End-Of-Rib marker BGP
179        // UPDATE message advertises this ability using a BGP capability
180        // (RFC 5492) which is expressed as an optional parameter type 2
181        // with a capability code 64 (from RFC 4274).
182
183        // Optional Parameters:
184        //
185        // This field contains a list of optional parameters, in which
186        // each parameter is encoded as a <Parameter Type, Parameter
187        // Length, Parameter Value> triplet.
188        //
189        //  0                   1
190        //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
191        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...
192        // |  Parm. Type   | Parm. Length  |  Parameter Value (variable)
193        // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...
194        //
195        // Parameter Type is a one octet field that unambiguously
196        // identifies individual parameters.  Parameter Length is a one
197        // octet field that contains the length of the Parameter Value
198        // field in octets.  Parameter Value is a variable length field
199        // that is interpreted according to the value of the Parameter
200        // Type field.
201        //
202        // [RFC3392] defines the Capabilities Optional Parameter.
203        //
204        // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.2
205        // Note that RFC 3392 was obsoleted by RFC 5492
206        //
207        // Which leads us to...
208
209        // 4.  Capabilities Optional Parameter (Parameter Type 2):
210        //
211        // This is an Optional Parameter that is used by a BGP speaker to convey
212        // to its BGP peer the list of capabilities supported by the speaker.
213        // The encoding of BGP Optional Parameters is specified in Section 4.2
214        // of [RFC4271].  The parameter type of the Capabilities Optional
215        // Parameter is 2.
216        //
217        // The parameter contains one or more triples <Capability Code,
218        // Capability Length, Capability Value>, where each triple is encoded as
219        // shown below:
220        //
221        //        +------------------------------+
222        //        | Capability Code (1 octet)    |
223        //        +------------------------------+
224        //        | Capability Length (1 octet)  |
225        //        +------------------------------+
226        //        | Capability Value (variable)  |
227        //        ~                              ~
228        //        +------------------------------+
229        //
230        // The use and meaning of these fields are as follows:
231        //
232        //    Capability Code:
233        //
234        //       Capability Code is a one-octet unsigned binary integer that
235        //       unambiguously identifies individual capabilities.
236        //
237        //    Capability Length:
238        //
239        //       Capability Length is a one-octet unsigned binary integer that
240        //       contains the length of the Capability Value field in octets.
241        //
242        //    Capability Value:
243        //
244        //       Capability Value is a variable-length field that is interpreted
245        //       according to the value of the Capability Code field.
246        //
247        // From: https://datatracker.ietf.org/doc/html/rfc5492#section-4
248        //
249        // Which leads us further on to ...
250
251        // 3.  Graceful Restart Capability
252        //
253        // The Graceful Restart Capability is a new BGP capability [BGP-CAP]
254        // that can be used by a BGP speaker to indicate its ability to preserve
255        // its forwarding state during BGP restart.  It can also be used to
256        // convey to its peer its intention of generating the End-of-RIB marker
257        // upon the completion of its initial routing updates.
258        //
259        // This capability is defined as follows:
260        //
261        //    Capability code: 64
262        //
263        //    Capability length: variable
264        //
265        //    Capability value: Consists of the "Restart Flags" field, "Restart
266        //    Time" field, and 0 to 63 of the tuples <AFI, SAFI, Flags for
267        //    address family> as follows:
268        //
269        //       +--------------------------------------------------+
270        //       | Restart Flags (4 bits)                           |
271        //       +--------------------------------------------------+
272        //       | Restart Time in seconds (12 bits)                |
273        //       +--------------------------------------------------+
274        //       | Address Family Identifier (16 bits)              |
275        //       +--------------------------------------------------+
276        //       | Subsequent Address Family Identifier (8 bits)    |
277        //       +--------------------------------------------------+
278        //       | Flags for Address Family (8 bits)                |
279        //       +--------------------------------------------------+
280        //       | ...                                              |
281        //       +--------------------------------------------------+
282        //       | Address Family Identifier (16 bits)              |
283        //       +--------------------------------------------------+
284        //       | Subsequent Address Family Identifier (8 bits)    |
285        //       +--------------------------------------------------+
286        //       | Flags for Address Family (8 bits)                |
287        //       +--------------------------------------------------+
288        //
289        // The use and meaning of the fields are as follows:
290        //
291        //    Restart Flags:
292        //
293        //       This field contains bit flags related to restart.
294        //
295        //           0 1 2 3
296        //          +-+-+-+-+
297        //          |R|Resv.|
298        //          +-+-+-+-+
299        //
300        //       The most significant bit is defined as the Restart State (R)
301        //       bit, which can be used to avoid possible deadlock caused by
302        //       waiting for the End-of-RIB marker when multiple BGP speakers
303        //       peering with each other restart.  When set (value 1), this bit
304        //       indicates that the BGP speaker has restarted, and its peer MUST
305        //       NOT wait for the End-of-RIB marker from the speaker before
306        //       advertising routing information to the speaker.
307        //
308        //       The remaining bits are reserved and MUST be set to zero by the
309        //       sender and ignored by the receiver.
310        //
311        //    Restart Time:
312        //
313        //       This is the estimated time (in seconds) it will take for the
314        //       BGP session to be re-established after a restart.  This can be
315        //       used to speed up routing convergence by its peer in case that
316        //       the BGP speaker does not come back after a restart.
317        //
318        //    Address Family Identifier (AFI), Subsequent Address Family
319        //       Identifier (SAFI):
320        //
321        //       The AFI and SAFI, taken in combination, indicate that Graceful
322        //       Restart is supported for routes that are advertised with the
323        //       same AFI and SAFI.  Routes may be explicitly associated with a
324        //       particular AFI and SAFI using the encoding of [BGP-MP] or
325        //       implicitly associated with <AFI=IPv4, SAFI=Unicast> if using
326        //       the encoding of [BGP-4].
327        //
328        //    Flags for Address Family:
329        //
330        //       This field contains bit flags relating to routes that were
331        //       advertised with the given AFI and SAFI.
332        //
333        //           0 1 2 3 4 5 6 7
334        //          +-+-+-+-+-+-+-+-+
335        //          |F|   Reserved  |
336        //          +-+-+-+-+-+-+-+-+
337        //
338        //       The most significant bit is defined as the Forwarding State (F)
339        //       bit, which can be used to indicate whether the forwarding state
340        //       for routes that were advertised with the given AFI and SAFI has
341        //       indeed been preserved during the previous BGP restart.  When
342        //       set (value 1), the bit indicates that the forwarding state has
343        //       been preserved.
344        //
345        //       The remaining bits are reserved and MUST be set to zero by the
346        //       sender and ignored by the receiver.
347        // From: https://datatracker.ietf.org/doc/html/rfc4724#section-3
348
349        // BGP optional parameters: optp_len, optp_params
350        // Where:
351        //   optp_len = octet len of optp_params
352        //   optp_params = [(optpi_type, optpi_len, optpi_value), ...]
353        //     Where:
354        //       optpi_type = 2 (the RFC 5492 capabilities optional parameter code)
355        //       optpi_len = the octet len of optpi_vals
356        //       optpi_value = [(cap_code, cap_len, cap_val), ...]
357        //         Where there is a single tuple with:
358        //           cap_code = 64 (the RFC 4724 graceful restart capability code)
359        //           cap_len  = 2 (two bytes for 4-bit flags + 12-bit restart time)
360        //           cap_val  = 0 (0 4-bit flags + 0 12-bit restart time)
361        //       }
362        //   }
363
364        // innermost layer
365        let cap_code = 64u8;
366        let cap_len = 2u8;
367        let cap_val = 0u16;
368
369        // middle layer
370        let optpi_type = 2u8;
371        let mut optpi_value = Vec::<u8>::new();
372        optpi_value.push(cap_code);
373        optpi_value.push(cap_len);
374        optpi_value.extend_from_slice(&cap_val.to_be_bytes());
375        let optpi_len = u8::try_from(optpi_value.len()).unwrap();
376
377        // outer layer
378        let mut optp_params = Vec::<u8>::new();
379        optp_params.push(optpi_type);
380        optp_params.push(optpi_len);
381        optp_params.append(&mut optpi_value);
382        let optp_len = u8::try_from(optp_params.len()).unwrap();
383
384        // extend the BGP OPEN message with the optional parameters
385        bgp_msg_buf.extend_from_slice(&[optp_len]);
386        bgp_msg_buf.extend_from_slice(&optp_params);
387    }
388
389    // Finalize BGP message
390    finalize_bgp_msg_len(&mut bgp_msg_buf);
391    buf.extend_from_slice(&bgp_msg_buf);
392
393    for (typ, val) in information_tlvs {
394        push_bmp_information_tlv(&mut buf, typ, val.as_bytes());
395    }
396
397    finalize_bmp_msg_len(&mut buf);
398    
399    (buf.freeze(), warnings)
400}
401
402#[allow(clippy::vec_init_then_push)]
403pub fn mk_route_monitoring_msg(
404    per_peer_header: &PerPeerHeader,
405    withdrawals: &Prefixes,
406    announcements: &Announcements,
407    extra_path_attributes: &[u8],
408) -> (Bytes, Vec<String>) {
409    let (bgp_msg_buf, mut warnings) =
410        mk_bgp_update(per_peer_header, withdrawals, announcements, extra_path_attributes);
411    let (bytes, mut more_warnings) = mk_raw_route_monitoring_msg(per_peer_header, bgp_msg_buf);
412
413    warnings.append(&mut more_warnings);
414
415    (bytes, warnings)
416}
417
418// Returns the generated bytes and a, possibly empty, set of warning messages.
419pub fn mk_raw_route_monitoring_msg(
420    per_peer_header: &PerPeerHeader,
421    bgp_msg_buf: Bytes,
422) -> (Bytes, Vec<String>) {
423    // 4.6.  Route Monitoring
424    //
425    // "Following the common BMP header and per-peer header is a BGP Update
426    //  PDU."
427    //
428    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.6
429
430    let mut buf = BytesMut::new();
431    push_bmp_common_header(&mut buf, MessageType::RouteMonitoring);
432    let warnings = push_bmp_per_peer_header(&mut buf, per_peer_header);
433    buf.extend_from_slice(&bgp_msg_buf);
434    finalize_bmp_msg_len(&mut buf);
435    
436    (buf.freeze(), warnings)
437}
438
439// Returns the generated bytes and a, possibly empty, set of warning messages.
440#[allow(clippy::vec_init_then_push)]
441pub fn mk_bgp_update(
442    per_peer_header: &PerPeerHeader,
443    withdrawals: &Prefixes,
444    announcements: &Announcements,
445    extra_path_attributes: &[u8],
446) -> (Bytes, Vec<String>) {
447    let mut warnings = vec![];
448
449    // 4.3. UPDATE Message Format
450    //
451    // "The UPDATE message always includes the fixed-size BGP
452    //  header, and also includes the other fields, as shown below (note,
453    //  some of the shown fields may not be present in every UPDATE message):"
454    //
455    //      +-----------------------------------------------------+
456    //      |   Withdrawn Routes Length (2 octets)                |
457    //      +-----------------------------------------------------+
458    //      |   Withdrawn Routes (variable)                       |
459    //      +-----------------------------------------------------+
460    //      |   Total Path Attribute Length (2 octets)            |
461    //      +-----------------------------------------------------+
462    //      |   Path Attributes (variable)                        |
463    //      +-----------------------------------------------------+
464    //      |   Network Layer Reachability Information (variable) |
465    //      +-----------------------------------------------------+
466    //
467    // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
468
469    let mut buf = BytesMut::new();
470
471    // Fixed size BGP header
472    buf.resize(buf.len() + 16, 0xFFu8);
473    // marker
474    buf.resize(buf.len() + 2, 0);
475    // placeholder length, to be replaced later
476    buf.extend_from_slice(&2u8.to_be_bytes());
477    // 2 - UPDATE
478
479    // Other fields
480    // Route withdrawals
481    // "Withdrawn Routes Length:
482    //
483    //  This 2-octets unsigned integer indicates the total length of
484    //  the Withdrawn Routes field in octets.  Its value allows the
485    //  length of the Network Layer Reachability Information field to
486    //  be determined, as specified below.
487    //
488    //  A value of 0 indicates that no routes are being withdrawn from
489    //  service, and that the WITHDRAWN ROUTES field is not present in
490    //  this UPDATE message.
491    //
492    //  Withdrawn Routes:
493    //
494    //  This is a variable-length field that contains a list of IP
495    //  address prefixes for the routes that are being withdrawn from
496    //  service.  Each IP address prefix is encoded as a 2-tuple of the
497    //  form <length, prefix>, whose fields are described below:
498    //
499    //           +---------------------------+
500    //           |   Length (1 octet)        |
501    //           +---------------------------+
502    //           |   Prefix (variable)       |
503    //           +---------------------------+
504    //
505    //  The use and the meaning of these fields are as follows:
506    //
507    //  a) Length:
508    //
509    //     The Length field indicates the length in bits of the IP
510    //     address prefix.  A length of zero indicates a prefix that
511    //     matches all IP addresses (with prefix, itself, of zero
512    //     octets).
513    //
514    //  b) Prefix:
515    //
516    //     The Prefix field contains an IP address prefix, followed by
517    //     the minimum number of trailing bits needed to make the end
518    //     of the field fall on an octet boundary.  Note that the value
519    //     of trailing bits is irrelevant."
520    //
521    // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
522    let mut withdrawn_routes = BytesMut::new();
523    let mut mp_unreach_nlri = BytesMut::new();
524
525    for prefix in withdrawals.iter() {
526        let (addr, len) = prefix.addr_and_len();
527        match addr {
528            IpAddr::V4(addr) => {
529                withdrawn_routes.extend_from_slice(&[len]);
530                if len > 0 {
531                    let min_bytes = div_ceil(len, 8) as usize;
532                    withdrawn_routes
533                        .extend_from_slice(&addr.octets()[..min_bytes]);
534                }
535            }
536            IpAddr::V6(addr) => {
537                // https://datatracker.ietf.org/doc/html/rfc4760#section-4
538                if mp_unreach_nlri.is_empty() {
539                    mp_unreach_nlri.put_u16(Afi::Ipv6.into());
540                    mp_unreach_nlri.put_u8(
541                        u8::from(Safi::Unicast) | u8::from(Safi::Multicast),
542                    );
543                }
544                mp_unreach_nlri.extend_from_slice(&[len]);
545                if len > 0 {
546                    let min_bytes = div_ceil(len, 8) as usize;
547                    mp_unreach_nlri
548                        .extend_from_slice(&addr.octets()[..min_bytes]);
549                }
550            }
551        }
552    }
553    let num_withdrawn_route_bytes =
554        u16::try_from(withdrawn_routes.len()).unwrap();
555    buf.extend_from_slice(&num_withdrawn_route_bytes.to_be_bytes());
556    // N withdrawn route bytes
557    if num_withdrawn_route_bytes > 0 {
558        buf.extend(&withdrawn_routes); // the withdrawn routes
559    }
560
561    // Route announcements
562    // "Total Path Attribute Length:
563    //
564    //  This 2-octet unsigned integer indicates the total length of the
565    //  Path Attributes field in octets.  Its value allows the length
566    //  of the Network Layer Reachability field to be determined as
567    //  specified below.
568    //
569    //  A value of 0 indicates that neither the Network Layer
570    //  Reachability Information field nor the Path Attribute field is
571    //  present in this UPDATE message.
572    //
573    //  Path Attributes:
574    //
575    //  A variable-length sequence of path attributes is present in
576    //  every UPDATE message, except for an UPDATE message that carries
577    //  only the withdrawn routes.  Each path attribute is a triple
578    //  <attribute type, attribute length, attribute value> of variable
579    //  length.
580    //
581    //  Attribute Type is a two-octet field that consists of the
582    //  Attribute Flags octet, followed by the Attribute Type Code
583    //  octet.
584    //
585    //        0                   1
586    //        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
587    //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588    //        |  Attr. Flags  |Attr. Type Code|
589    //        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
590    //
591    // ...
592    //
593    // "Network Layer Reachability Information:
594    //
595    //  This variable length field contains a list of IP address
596    //  prefixes.  The length, in octets, of the Network Layer
597    //  Reachability Information is not encoded explicitly, but can be
598    //  calculated as:
599    //
600    //        UPDATE message Length - 23 - Total Path Attributes Length
601    //        - Withdrawn Routes Length
602    //
603    //  where UPDATE message Length is the value encoded in the fixed-
604    //  size BGP header, Total Path Attribute Length, and Withdrawn
605    //  Routes Length are the values encoded in the variable part of
606    //  the UPDATE message, and 23 is a combined length of the fixed-
607    //  size BGP header, the Total Path Attribute Length field, and the
608    //  Withdrawn Routes Length field.
609    //
610    //  Reachability information is encoded as one or more 2-tuples of
611    //  the form <length, prefix>, whose fields are described below:
612    //
613    //           +---------------------------+
614    //           |   Length (1 octet)        |
615    //           +---------------------------+
616    //           |   Prefix (variable)       |
617    //           +---------------------------+
618    //
619    //  The use and the meaning of these fields are as follows:
620    //
621    //  a) Length:
622    //
623    //     The Length field indicates the length in bits of the IP
624    //     address prefix.  A length of zero indicates a prefix that
625    //     matches all IP addresses (with prefix, itself, of zero
626    //     octets).
627    //
628    //  b) Prefix:
629    //
630    //     The Prefix field contains an IP address prefix, followed by
631    //     enough trailing bits to make the end of the field fall on an
632    //     octet boundary.  Note that the value of the trailing bits is
633    //     irrelevant."
634    //
635    // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
636    match announcements {
637        Announcements::None => {
638            buf.extend_from_slice(&0u16.to_be_bytes()); // 0 path attributes and no NLRI field
639        }
640        Announcements::Some {
641            origin,
642            as_path,
643            next_hop,
644            communities,
645            prefixes,
646        } => {
647            fn push_attributes(
648                out_bytes: &mut Vec<u8>,
649                r#type: PathAttributeType,
650                pa_bytes: &[u8],
651            ) {
652                // Path Attributes:
653                // 
654                // A variable-length sequence of path attributes is present in
655                // every UPDATE message, except for an UPDATE message that carries
656                // only the withdrawn routes.  Each path attribute is a triple
657                // <attribute type, attribute length, attribute value> of variable
658                // length.
659                // 
660                // Attribute Type is a two-octet field that consists of the
661                // Attribute Flags octet, followed by the Attribute Type Code
662                // octet.
663                // 
664                //       0                   1
665                //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
666                //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
667                //       |  Attr. Flags  |Attr. Type Code|
668                //       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
669                // 
670                // The high-order bit (bit 0) of the Attribute Flags octet is the
671                // Optional bit.  It defines whether the attribute is optional (if
672                // set to 1) or well-known (if set to 0).
673                // 
674                // The second high-order bit (bit 1) of the Attribute Flags octet
675                // is the Transitive bit.  It defines whether an optional
676                // attribute is transitive (if set to 1) or non-transitive (if set
677                // to 0).
678                // 
679                // For well-known attributes, the Transitive bit MUST be set to 1.
680                // (See Section 5 for a discussion of transitive attributes.)
681                // 
682                // The third high-order bit (bit 2) of the Attribute Flags octet
683                // is the Partial bit.  It defines whether the information
684                // contained in the optional transitive attribute is partial (if
685                // set to 1) or complete (if set to 0).  For well-known attributes
686                // and for optional non-transitive attributes, the Partial bit
687                // MUST be set to 0.
688                // 
689                // The fourth high-order bit (bit 3) of the Attribute Flags octet
690                // is the Extended Length bit.  It defines whether the Attribute
691                // Length is one octet (if set to 0) or two octets (if set to 1).
692                // 
693                // The lower-order four bits of the Attribute Flags octet are
694                // unused.  They MUST be zero when sent and MUST be ignored when
695                // received.
696                // 
697                // The Attribute Type Code octet contains the Attribute Type Code.
698                // Currently defined Attribute Type Codes are discussed in Section
699                // 5.
700                // 
701                // If the Extended Length bit of the Attribute Flags octet is set
702                // to 0, the third octet of the Path Attribute contains the length
703                // of the attribute data in octets.
704                // 
705                // If the Extended Length bit of the Attribute Flags octet is set
706                // to 1, the third and fourth octets of the path attribute contain
707                // the length of the attribute data in octets.
708                // 
709                // The remaining octets of the Path Attribute represent the
710                // attribute value and are interpreted according to the Attribute
711                // Flags and the Attribute Type Code.  The supported Attribute
712                // Type Codes, and their attribute values and uses are as follows:
713
714                let len = pa_bytes.len();
715
716                let (optional, transitive, partial) = match r#type {
717                    PathAttributeType::AsPath
718                    | PathAttributeType::NextHop
719                    | PathAttributeType::Origin => (false, true, false),
720                    PathAttributeType::Communities
721                    | PathAttributeType::ExtendedCommunities
722                    | PathAttributeType::LargeCommunities => (true, true, false),
723                    PathAttributeType::MpReachNlri => (true, false, false),
724                    _ => todo!(),
725                };
726
727                let mut flags = 0u8;
728                if optional {
729                    flags |= 0b1000_0000;
730                }
731                if !optional || transitive {
732                    flags |= 0b0100_0000;
733                }
734                if !optional || !transitive {
735                    flags &= 0b1101_1111;
736                } else if partial {
737                    flags |= 0b0010_0000;
738                }
739                if len > 255 {
740                    flags |= 0b0001_0000;
741                }
742
743                out_bytes.put_u8(flags); // attr. flags
744                out_bytes.put_u8(u8::from(r#type)); // attr. type
745                if len <= 255 {
746                    out_bytes.put_u8(u8::try_from(len).unwrap()); // attr. octet length
747                } else {
748                    out_bytes.put_u16(u16::try_from(len).unwrap()); // attr. octet length
749                };
750
751                out_bytes.extend_from_slice(pa_bytes);
752            }
753
754            let mut path_attributes = Vec::<u8>::new();
755
756            // -------------------------------------------------------------------
757            // "ORIGIN (Type Code 1):
758            //
759            //  ORIGIN is a well-known mandatory attribute that defines the origin
760            //  of the path information."
761            //
762            // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
763            push_attributes(
764                &mut path_attributes,
765                PathAttributeType::Origin,
766                &[origin.into()],
767            );
768
769            // -------------------------------------------------------------------
770            // "AS_PATH (Type Code 2):
771            //
772            //  AS_PATH is a well-known mandatory attribute that is composed of a
773            //  sequence of AS path segments.  Each AS path segment is represented
774            //  by a triple <path segment type, path segment length, path segment
775            //  value>."
776            //
777            // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
778            let mut as_path_attr_value_bytes = Vec::<u8>::new();
779
780            let as_path = if per_peer_header.is_legacy_two_byte_as_path_format() {
781                match as_path.try_to_asn16_path::<Vec<u8>>() {
782                    Ok(as_path) => as_path,
783                    Err(err) => {
784                        warnings.push(format!("RFC 7854 section 4.2 Per-Peer Header violation: Peer Flags A-bit is SET but should be unset because the AS PATH being encoded contains ASNs that cannot be encoded in 16-bits: {err}"));
785                        as_path.to_as_path::<Vec<u8>>().unwrap()
786                    }
787                }
788            } else {
789                as_path.to_as_path::<Vec<u8>>().unwrap()
790            };
791
792            // sequence of AS path segments [(seg. type, seg. len, seg. val), ...]
793            for segment in as_path.segments() {
794                segment.compose(&mut as_path_attr_value_bytes).unwrap();
795            }
796
797            push_attributes(
798                &mut path_attributes,
799                PathAttributeType::AsPath,
800                &as_path_attr_value_bytes,
801            );
802
803            // -------------------------------------------------------------------
804            // "NEXT_HOP (Type Code 3):
805            //
806            //  This is a well-known mandatory attribute that defines the (unicast)
807            //  IP address of the router that SHOULD be used as the next hop to the
808            //  destinations listed in the Network Layer Reachability Information
809            //  field of the UPDATE message."
810            //
811            // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.3
812            if let NextHop::Unicast(IpAddr::V4(addr)) = next_hop.0 {
813                push_attributes(
814                    &mut path_attributes,
815                    PathAttributeType::NextHop,
816                    &addr.octets(),
817                );
818            }
819
820            // -------------------------------------------------------------------
821            // "COMMUNITIES attribute:
822            //
823            //  This document creates the COMMUNITIES path attribute is an optional
824            //  transitive attribute of variable length.  The attribute consists of a
825            //  set of four octet values, each of which specify a community.  All
826            //  routes with this attribute belong to the communities listed in the
827            //  attribute.
828            //
829            //  The COMMUNITIES attribute has Type Code 8.
830            //
831            //  Communities are treated as 32 bit values,  however for administrative
832            //  assignment,  the following presumptions may be made:
833            //
834            //  The community attribute values ranging from 0x0000000 through
835            //  0x0000FFFF and 0xFFFF0000 through 0xFFFFFFFF are hereby reserved.
836            //
837            //  The rest of the community attribute values shall be encoded using an
838            //  autonomous system number in the first two octets.  The semantics of
839            //  the final two octets may be defined by the autonomous system (e.g. AS
840            //  690 may define research, educational and commercial community values
841            //  that may be used for policy routing as defined by the operators of
842            //  that AS using community attribute values 0x02B20000 through
843            //  0x02B2FFFF)."
844            //
845            // From: https://www.rfc-editor.org/rfc/rfc1997.html
846            if !communities.is_empty() {
847                let mut communities_attribute_bytes = Vec::<u8>::new();
848                let mut extended_communities_attribute_bytes =
849                    Vec::<u8>::new();
850                let mut large_communities_attribute_bytes = Vec::<u8>::new();
851
852                for community in communities.deref() {
853                    match community {
854                        Community::Standard(c) => communities_attribute_bytes
855                            .extend_from_slice(&c.to_raw()),
856                        Community::Extended(c) => {
857                            extended_communities_attribute_bytes
858                                .extend_from_slice(&c.to_raw())
859                        }
860                        Community::Ipv6Extended(_) => todo!(),
861                        Community::Large(c) => {
862                            large_communities_attribute_bytes
863                                .extend_from_slice(&c.to_raw())
864                        }
865                    }
866                }
867
868                if !communities_attribute_bytes.is_empty() {
869                    push_attributes(
870                        &mut path_attributes,
871                        PathAttributeType::Communities,
872                        &communities_attribute_bytes,
873                    );
874                }
875
876                if !extended_communities_attribute_bytes.is_empty() {
877                    push_attributes(
878                        &mut path_attributes,
879                        PathAttributeType::ExtendedCommunities,
880                        &extended_communities_attribute_bytes,
881                    );
882                }
883
884                if !large_communities_attribute_bytes.is_empty() {
885                    push_attributes(
886                        &mut path_attributes,
887                        PathAttributeType::LargeCommunities,
888                        &large_communities_attribute_bytes,
889                    );
890                }
891            }
892
893            // Now add the list of NLRI IP addresses
894            let mut announced_routes = Vec::<u8>::new();
895            let mut mp_reach_nlri = BytesMut::new();
896
897            for prefix in prefixes.iter() {
898                let (addr, len) = prefix.addr_and_len();
899                match addr {
900                    IpAddr::V4(addr) => {
901                        announced_routes.extend_from_slice(&[len]);
902                        if len > 0 {
903                            let min_bytes = div_ceil(len, 8) as usize;
904                            announced_routes.extend_from_slice(
905                                &addr.octets()[..min_bytes],
906                            );
907                        }
908                    }
909                    IpAddr::V6(addr) => {
910                        // https://datatracker.ietf.org/doc/html/rfc4760#section-3
911                        if mp_reach_nlri.is_empty() {
912                            mp_reach_nlri.put_u16(Afi::Ipv6.into());
913                            mp_reach_nlri.put_u8(u8::from(Safi::Unicast));
914                            if let NextHop::Unicast(IpAddr::V6(addr)) = next_hop.0 {
915                                mp_reach_nlri
916                                    .put_u8(addr.octets().len() as u8);
917                                mp_reach_nlri
918                                    .extend_from_slice(&addr.octets());
919                            } else {
920                                unreachable!();
921                            }
922                            mp_reach_nlri.put_u8(0u8); // reserved
923                        }
924                        mp_reach_nlri.extend_from_slice(&[len]);
925                        if len > 0 {
926                            let min_bytes = div_ceil(len, 8) as usize;
927                            mp_reach_nlri.extend_from_slice(
928                                &addr.octets()[..min_bytes],
929                            );
930                        }
931                    }
932                }
933            }
934
935            if !mp_reach_nlri.is_empty() {
936                push_attributes(
937                    &mut path_attributes,
938                    PathAttributeType::MpReachNlri,
939                    &mp_reach_nlri,
940                );
941            }
942
943            let num_path_attribute_bytes = u16::try_from(
944                path_attributes.len() + extra_path_attributes.len(),
945            )
946            .unwrap();
947            buf.extend_from_slice(&num_path_attribute_bytes.to_be_bytes()); // N path attribute bytes
948            buf.extend_from_slice(&path_attributes);
949            buf.extend_from_slice(extra_path_attributes);
950
951            if !announced_routes.is_empty() {
952                buf.extend_from_slice(&announced_routes); // the announced routes
953            }
954        }
955    }
956
957    // Finalize BGP message
958    finalize_bgp_msg_len(&mut buf);
959    
960    (buf.freeze(), warnings)
961}
962
963// Returns the generated bytes and a, possibly empty, set of warning messages.
964pub fn mk_peer_down_notification_msg(
965    per_peer_header: &PerPeerHeader,
966) -> (Bytes, Vec<String>) {
967    let mut buf = BytesMut::new();
968    push_bmp_common_header(&mut buf, MessageType::PeerDownNotification);
969    let warnings = push_bmp_per_peer_header(&mut buf, per_peer_header);
970
971    // 4.9.  Peer Down Notification
972    //
973    //  0                   1                   2                   3
974    //  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
975    // +-+-+-+-+-+-+-+-+
976    // |    Reason     |
977    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
978    // |            Data (present if Reason = 1, 2 or 3)               |
979    // ~                                                               ~
980    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
981    //
982    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.9
983
984    buf.extend_from_slice(&5u8.to_be_bytes()); // reason code 5
985
986    finalize_bmp_msg_len(&mut buf);
987    
988    (buf.freeze(), warnings)
989}
990
991// Returns the generated bytes and a, possibly empty, set of warning messages.
992pub fn mk_statistics_report_msg(per_peer_header: &PerPeerHeader) -> (Bytes, Vec<String>) {
993    // 4.8.  Stats Reports
994    //
995    // "Following the common BMP header and per-peer header is a 4-byte field
996    //  that indicates the number of counters in the stats message where each
997    //  counter is encoded as a TLV."
998    //
999    //     0                   1                   2                   3
1000    //     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
1001    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1002    //    |                        Stats Count                            |
1003    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1004    //
1005    //  Each counter is encoded as follows:
1006    //
1007    //     0                   1                   2                   3
1008    //     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
1009    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1010    //    |         Stat Type             |          Stat Len             |
1011    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1012    //    |                        Stat Data                              |
1013    //    ~                                                               ~
1014    //    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1015    //
1016    //  o  Stat Type (2 bytes): Defines the type of the statistic carried in
1017    //     the Stat Data field.
1018    //
1019    //  o  Stat Len (2 bytes): Defines the length of the Stat Data field.
1020    //
1021    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.8
1022
1023    let mut buf = BytesMut::new();
1024    push_bmp_common_header(&mut buf, MessageType::StatisticsReport);
1025    let warnings = push_bmp_per_peer_header(&mut buf, per_peer_header);
1026
1027    buf.extend_from_slice(&0u32.to_be_bytes()); // zero stats
1028
1029    finalize_bmp_msg_len(&mut buf);
1030    
1031    (buf.freeze(), warnings)
1032}
1033
1034pub fn mk_termination_msg() -> Bytes {
1035    let mut buf = BytesMut::new();
1036    push_bmp_common_header(&mut buf, MessageType::TerminationMessage);
1037
1038    // 4.5. Termination Message
1039    //
1040    // "The termination message consists of the common BMP header followed by
1041    //  one or more TLVs containing information about the reason for the
1042    //  termination, as follows:"
1043    //
1044    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.5
1045
1046    // 4.4 Information TLV
1047    //
1048    //  0                   1                   2                   3
1049    //  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
1050    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1051    // |          Information Type     |       Information Length      |
1052    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1053    // |                 Information (variable)                        |
1054    // ~                                                               ~
1055    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1056    //
1057    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.4
1058
1059    push_bmp_termination_tlv(
1060        &mut buf,
1061        TerminationInformation::AdminClose,
1062        &[0u8, 0u8],
1063    );
1064
1065    finalize_bmp_msg_len(&mut buf);
1066    buf.freeze()
1067}
1068
1069fn finalize_bmp_msg_len(buf: &mut BytesMut) {
1070    let len_bytes: [u8; 4] = (buf.len() as u32).to_be_bytes();
1071    buf[1] = len_bytes[0];
1072    buf[2] = len_bytes[1];
1073    buf[3] = len_bytes[2];
1074    buf[4] = len_bytes[3];
1075}
1076
1077fn finalize_bgp_msg_len(buf: &mut BytesMut) {
1078    assert!(buf.len() >= 19);
1079    assert!(buf.len() <= 4096);
1080
1081    let len_bytes: [u8; 2] = (buf.len() as u16).to_be_bytes();
1082    buf[16] = len_bytes[0];
1083    buf[17] = len_bytes[1];
1084}
1085
1086fn push_bmp_common_header(buf: &mut BytesMut, msg_type: MessageType) {
1087    //  0                   1                   2                   3
1088    //  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
1089    // +-+-+-+-+-+-+-+-+
1090    // |    Version    |
1091    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1092    // |                        Message Length                         |
1093    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1094    // |   Msg. Type   |
1095    // +---------------+
1096    //
1097    // From: https://datatracker.ietf.org/doc/html/rfc4271#section-4.1
1098    buf.extend_from_slice(&[3u8]); // version 3
1099    buf.resize(buf.len() + 4, 0u8); // placeholder length, to be replaced later
1100    buf.extend_from_slice(&u8::from(msg_type).to_be_bytes());
1101}
1102
1103#[derive(Debug, PartialEq, Eq)]
1104pub struct PerPeerHeader {
1105    pub peer_type: MyPeerType,
1106    pub peer_flags: u8,
1107    pub peer_distinguisher: [u8; 8],
1108    pub peer_address: IpAddr,
1109    pub peer_as: Asn,
1110    pub peer_bgp_id: [u8; 4],
1111}
1112
1113impl PerPeerHeader {
1114    fn is_ipv4(&self) -> bool {
1115        self.peer_flags & 0x80 == 0
1116    }
1117
1118    fn is_ipv6(&self) -> bool {
1119        self.peer_flags & 0x80 == 0x80
1120    }
1121
1122    fn is_legacy_two_byte_as_path_format(&self) -> bool {
1123        self.peer_flags & 0x20 == 0x20
1124    }
1125}
1126
1127pub fn mk_per_peer_header(peer_ip: &str, peer_as: u32) -> PerPeerHeader {
1128    PerPeerHeader {
1129        peer_type: PeerType::GlobalInstance.into(),
1130        peer_flags: 0,
1131        peer_distinguisher: [0u8; 8],
1132        peer_address: peer_ip.parse().unwrap(),
1133        peer_as: Asn::from_u32(peer_as),
1134        peer_bgp_id: [1u8, 2u8, 3u8, 4u8],
1135    }
1136}
1137
1138// Returns warnings about incorrect Per-Peer Header flags, if any.
1139fn push_bmp_per_peer_header(buf: &mut BytesMut, pph: &PerPeerHeader) -> Vec<String> {
1140    let mut warnings = vec![];
1141
1142    //  0                   1                   2                   3
1143    //  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
1144    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1145    // |   Peer Type   |  Peer Flags   |
1146    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1147    // |         Peer Distinguisher (present based on peer type)       |
1148    // |                                                               |
1149    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1150    // |                 Peer Address (16 bytes)                       |
1151    // ~                                                               ~
1152    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1153    // |                           Peer AS                             |
1154    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1155    // |                         Peer BGP ID                           |
1156    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1157    // |                    Timestamp (seconds)                        |
1158    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1159    // |                  Timestamp (microseconds)                     |
1160    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1161    //
1162    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.2
1163
1164    // Peer Flags (1 byte): These flags provide more information about
1165    //   the peer.  The flags are defined as follows:
1166    // 
1167    //                           0 1 2 3 4 5 6 7
1168    //                          +-+-+-+-+-+-+-+-+
1169    //                          |V|L|A| Reserved|
1170    //                          +-+-+-+-+-+-+-+-+
1171    // 
1172    //   *  The V flag indicates that the Peer address is an IPv6 address.
1173    //      For IPv4 peers, this is set to 0.
1174    // 
1175    //   *  The L flag, if set to 1, indicates that the message reflects
1176    //      the post-policy Adj-RIB-In (i.e., its path attributes reflect
1177    //      the application of inbound policy).  It is set to 0 if the
1178    //      message reflects the pre-policy Adj-RIB-In.  Locally sourced
1179    //      routes also carry an L flag of 1.  See Section 5 for further
1180    //      detail.  This flag has no significance when used with route
1181    //      mirroring messages (Section 4.7).
1182    // 
1183    //   *  The A flag, if set to 1, indicates that the message is
1184    //      formatted using the legacy 2-byte AS_PATH format.  If set to 0,
1185    //      the message is formatted using the 4-byte AS_PATH format
1186    //      [RFC6793].  A BMP speaker MAY choose to propagate the AS_PATH
1187    //      information as received from its peer, or it MAY choose to
1188    //      reformat all AS_PATH information into a 4-byte format
1189    //      regardless of how it was received from the peer.  In the latter
1190    //      case, AS4_PATH or AS4_AGGREGATOR path attributes SHOULD NOT be
1191    //      sent in the BMP UPDATE message.  This flag has no significance
1192    //      when used with route mirroring messages (Section 4.7).
1193    // 
1194    //   *  The remaining bits are reserved for future use.  They MUST be
1195    //      transmitted as 0 and their values MUST be ignored on receipt.
1196
1197    // "Timestamp: The time when the encapsulated routes were received (one
1198    //  may also think of this as the time when they were installed in the
1199    //  Adj-RIB-In), expressed in seconds and microseconds since midnight
1200    //  (zero hour), January 1, 1970 (UTC).  If zero, the time is
1201    //  unavailable.  Precision of the timestamp is implementation-dependent."
1202    //
1203    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.2
1204    let now = Utc::now();
1205    let epoch_seconds = u32::try_from(now.timestamp()).unwrap();
1206    let epoch_micros = now.timestamp_subsec_micros();
1207
1208    buf.put_u8(u8::from(*pph.peer_type));
1209    buf.put_u8(pph.peer_flags);
1210    buf.extend_from_slice(&pph.peer_distinguisher);
1211
1212    // "Peer Address: The remote IP address associated with the TCP session
1213    //  over which the encapsulated PDU was received.  It is 4 bytes long if
1214    //  an IPv4 address is carried in this field (with the 12 most significant
1215    //  bytes zero-filled) and 16 bytes long if an IPv6 address is carried in
1216    //  this field."
1217    //
1218    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.2
1219    match pph.peer_address {
1220        IpAddr::V4(addr) => {
1221            buf.resize(buf.len() + 12, 0u8);
1222            buf.extend_from_slice(&addr.octets());
1223            if pph.is_ipv6() {
1224                warnings.push(format!("RFC 7854 section 4.2 Per-Peer Header violation: Peer Flags V-bit is SET but should be unset because peer address {addr} is an IPv4 address, not IPv6."));
1225            }
1226        }
1227        IpAddr::V6(addr) => {
1228            buf.extend_from_slice(&addr.octets());
1229            if pph.is_ipv4() {
1230                warnings.push(format!("RFC 7854 section 4.2 Per-Peer Header violation: Peer Flags V-bit is NOT set but should be set because peer address {addr} is an IPv6 address, not IPv4."));
1231            }
1232        }
1233    }
1234
1235    buf.extend_from_slice(&pph.peer_as.into_u32().to_be_bytes()); // assumes 32-bit ASN
1236    buf.extend_from_slice(&pph.peer_bgp_id);
1237    buf.extend_from_slice(&epoch_seconds.to_be_bytes());
1238    buf.extend_from_slice(&epoch_micros.to_be_bytes());
1239
1240    warnings
1241}
1242
1243fn push_bmp_information_tlv(
1244    buf: &mut BytesMut,
1245    tlv_type: InformationTlvType,
1246    tlv_value: &[u8],
1247) {
1248    //  0                   1                   2                   3
1249    //  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
1250    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1251    // |          Information Type     |       Information Length      |
1252    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1253    // |                 Information (variable)                        |
1254    // ~                                                               ~
1255    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1256    //
1257    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.4
1258    buf.extend_from_slice(&information_tlv_type_to_be_bytes(tlv_type));
1259    buf.extend_from_slice(&(tlv_value.len() as u16).to_be_bytes());
1260    buf.extend_from_slice(tlv_value);
1261}
1262
1263fn push_bmp_termination_tlv(
1264    buf: &mut BytesMut,
1265    tlv_type: TerminationInformation,
1266    tlv_value: &[u8],
1267) {
1268    //  0                   1                   2                   3
1269    //  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
1270    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1271    // |          Information Type     |       Information Length      |
1272    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1273    // |                 Information (variable)                        |
1274    // ~                                                               ~
1275    // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1276    //
1277    // From: https://www.rfc-editor.org/rfc/rfc7854.html#section-4.4
1278    buf.extend_from_slice(&termination_tlv_type_to_be_bytes(tlv_type));
1279    buf.extend_from_slice(&(tlv_value.len() as u16).to_be_bytes());
1280    buf.extend_from_slice(tlv_value);
1281}
1282
1283fn information_tlv_type_to_be_bytes(typ: InformationTlvType) -> [u8; 2] {
1284    match typ {
1285        InformationTlvType::String => 0u16.to_be_bytes(),
1286        InformationTlvType::SysDesc => 1u16.to_be_bytes(),
1287        InformationTlvType::SysName => 2u16.to_be_bytes(),
1288        _ => unreachable!(),
1289    }
1290}
1291
1292fn termination_tlv_type_to_be_bytes(typ: TerminationInformation) -> [u8; 2] {
1293    match typ {
1294        TerminationInformation::CustomString(_) => 0u16.to_be_bytes(),
1295        TerminationInformation::AdminClose
1296        | TerminationInformation::Unspecified
1297        | TerminationInformation::OutOfResources
1298        | TerminationInformation::RedundantConnection
1299        | TerminationInformation::PermAdminClose => 1u16.to_be_bytes(),
1300        TerminationInformation::Undefined(_) => unreachable!(),
1301    }
1302}
1303
1304#[derive(Debug, PartialEq, Eq)]
1305pub struct MyPeerType(PeerType);
1306
1307impl From<PeerType> for MyPeerType {
1308    fn from(peer_type: PeerType) -> Self {
1309        MyPeerType(peer_type)
1310    }
1311}
1312
1313impl Deref for MyPeerType {
1314    type Target = PeerType;
1315
1316    fn deref(&self) -> &Self::Target {
1317        &self.0
1318    }
1319}
1320
1321impl FromStr for MyPeerType {
1322    type Err = anyhow::Error;
1323
1324    fn from_str(s: &str) -> Result<Self, Self::Err> {
1325        let peer_type = match s {
1326            "global" => PeerType::GlobalInstance,
1327            _ => todo!(),
1328        };
1329
1330        Ok(MyPeerType(peer_type))
1331    }
1332}
1333
1334#[derive(Default)]
1335pub struct Prefixes(Vec<Prefix>);
1336
1337impl Prefixes {
1338    pub fn new(prefixes: Vec<Prefix>) -> Self {
1339        Self(prefixes)
1340    }
1341}
1342
1343impl Deref for Prefixes {
1344    type Target = Vec<Prefix>;
1345
1346    fn deref(&self) -> &Self::Target {
1347        &self.0
1348    }
1349}
1350
1351impl FromStr for Prefixes {
1352    type Err = anyhow::Error;
1353
1354    fn from_str(s: &str) -> Result<Self, Self::Err> {
1355        match s.to_lowercase().as_str() {
1356            "" | "none" => Ok(Prefixes(vec![])),
1357
1358            _ => {
1359                let mut prefixes = Vec::new();
1360                for prefix_str in s.split(',') {
1361                    prefixes.push(prefix_str.parse()?);
1362                }
1363                Ok(Prefixes(prefixes))
1364            }
1365        }
1366    }
1367}
1368
1369// Based on `div_ceil()` from Rust nightly.
1370pub const fn div_ceil(lhs: u8, rhs: u8) -> u8 {
1371    let d = lhs / rhs;
1372    let r = lhs % rhs;
1373    if r > 0 && rhs > 0 {
1374        d + 1
1375    } else {
1376        d
1377    }
1378}
1379
1380pub struct MyOriginType(OriginType);
1381
1382impl Deref for MyOriginType {
1383    type Target = OriginType;
1384
1385    fn deref(&self) -> &Self::Target {
1386        &self.0
1387    }
1388}
1389
1390impl FromStr for MyOriginType {
1391    type Err = anyhow::Error;
1392
1393    fn from_str(s: &str) -> Result<Self, Self::Err> {
1394        match s {
1395            "i" => Ok(Self(OriginType::Igp)),
1396            "e" => Ok(Self(OriginType::Egp)),
1397            "?" => Ok(Self(OriginType::Incomplete)),
1398            _ => Ok(s.parse::<u8>()?.into()),
1399        }
1400    }
1401}
1402
1403impl From<u8> for MyOriginType {
1404    fn from(v: u8) -> Self {
1405        let origin_type = match v {
1406            0 => OriginType::Igp,
1407            1 => OriginType::Egp,
1408            2 => OriginType::Incomplete,
1409            _ => OriginType::Unimplemented(v),
1410        };
1411        Self(origin_type)
1412    }
1413}
1414
1415impl From<&MyOriginType> for u8 {
1416    fn from(v: &MyOriginType) -> Self {
1417        match v {
1418            MyOriginType(OriginType::Igp) => 0,
1419            MyOriginType(OriginType::Egp) => 1,
1420            MyOriginType(OriginType::Incomplete) => 2,
1421            MyOriginType(OriginType::Unimplemented(v)) => *v,
1422        }
1423    }
1424}
1425
1426pub struct MyAsPath(HopPath);
1427
1428impl Deref for MyAsPath {
1429    type Target = HopPath;
1430
1431    fn deref(&self) -> &Self::Target {
1432        &self.0
1433    }
1434}
1435
1436impl FromStr for MyAsPath {
1437    type Err = anyhow::Error;
1438
1439    fn from_str(s: &str) -> Result<Self, Self::Err> {
1440        let mut hop_path = HopPath::new();
1441        if s.starts_with('[') && s.ends_with(']') {
1442            let s = &s[1..s.len() - 1];
1443            for asn in s.split(',') {
1444                let asn: Asn = asn.parse()?;
1445                hop_path.append(asn);
1446            }
1447            Ok(Self(hop_path))
1448        } else {
1449            Err(anyhow::anyhow!("Expected [asn, ...]"))
1450        }
1451    }
1452}
1453
1454pub struct MyNextHop(NextHop);
1455
1456impl Deref for MyNextHop {
1457    type Target = NextHop;
1458
1459    fn deref(&self) -> &Self::Target {
1460        &self.0
1461    }
1462}
1463
1464impl FromStr for MyNextHop {
1465    type Err = anyhow::Error;
1466
1467    fn from_str(s: &str) -> Result<Self, Self::Err> {
1468        let ip_addr: IpAddr = s.parse()?;
1469        match ip_addr {
1470            IpAddr::V4(addr) => Ok(MyNextHop(NextHop::Unicast(IpAddr::V4(addr)))),
1471            IpAddr::V6(addr) => Ok(MyNextHop(NextHop::Unicast(IpAddr::V6(addr)))),
1472        }
1473    }
1474}
1475
1476pub struct MyCommunities(Vec<Community>);
1477
1478impl Deref for MyCommunities {
1479    type Target = Vec<Community>;
1480
1481    fn deref(&self) -> &Self::Target {
1482        &self.0
1483    }
1484}
1485
1486impl FromStr for MyCommunities {
1487    type Err = anyhow::Error;
1488
1489    fn from_str(s: &str) -> Result<Self, Self::Err> {
1490        match s.to_lowercase().as_str() {
1491            "" | "none" => Ok(MyCommunities(vec![])),
1492
1493            _ => {
1494                let mut communities = Vec::new();
1495                for community_str in s.split(',') {
1496                    communities.push(community_str.parse().unwrap());
1497                }
1498                Ok(MyCommunities(communities))
1499            }
1500        }
1501    }
1502}
1503
1504#[derive(Default)]
1505pub enum Announcements {
1506    #[default]
1507    None,
1508    Some {
1509        origin: MyOriginType,
1510        as_path: MyAsPath,
1511        next_hop: MyNextHop,
1512        communities: MyCommunities,
1513        prefixes: Prefixes,
1514    },
1515}
1516
1517impl FromStr for Announcements {
1518    type Err = anyhow::Error;
1519
1520    fn from_str(s: &str) -> Result<Self, Self::Err> {
1521        match s.to_lowercase().as_str() {
1522            "" | "none" => Ok(Self::None),
1523
1524            _ => {
1525                let parts: Vec<&str> = s.splitn(5, ' ').collect();
1526                assert_eq!(parts.len(), 5);
1527                let origin = parts[0].parse().unwrap();
1528                let as_path = parts[1].parse().unwrap();
1529                let next_hop = parts[2].parse().unwrap();
1530                let communities = parts[3].parse().unwrap();
1531                let prefixes = parts[4].parse().unwrap();
1532                Ok(Self::Some {
1533                    origin,
1534                    as_path,
1535                    next_hop,
1536                    communities,
1537                    prefixes,
1538                })
1539            }
1540        }
1541    }
1542}