bgpkit_parser/parser/
utils.rs

1/*!
2Provides IO utility functions for read bytes of different length and converting to corresponding structs.
3*/
4use ipnet::{IpNet, Ipv4Net, Ipv6Net};
5use std::convert::TryFrom;
6use std::{
7    io,
8    net::{Ipv4Addr, Ipv6Addr},
9};
10
11use crate::error::ParserError;
12use crate::models::*;
13use crate::ParserError::TruncatedMsg;
14use bytes::{Buf, BufMut, Bytes, BytesMut};
15use log::debug;
16use regex::Regex;
17use std::net::IpAddr;
18
19impl ReadUtils for Bytes {}
20
21// Allow reading IPs from Reads
22pub trait ReadUtils: Buf {
23    #[inline]
24    fn has_n_remaining(&self, n: usize) -> Result<(), ParserError> {
25        let remaining = self.remaining();
26        if remaining < n {
27            Err(TruncatedMsg(format!(
28                "not enough bytes to read. remaining: {remaining}, required: {n}"
29            )))
30        } else {
31            Ok(())
32        }
33    }
34
35    #[inline]
36    fn read_u8(&mut self) -> Result<u8, ParserError> {
37        self.has_n_remaining(1)?;
38        Ok(self.get_u8())
39    }
40
41    #[inline]
42    fn read_u16(&mut self) -> Result<u16, ParserError> {
43        self.has_n_remaining(2)?;
44        Ok(self.get_u16())
45    }
46
47    #[inline]
48    fn read_u32(&mut self) -> Result<u32, ParserError> {
49        self.has_n_remaining(4)?;
50        Ok(self.get_u32())
51    }
52
53    #[inline]
54    fn read_u64(&mut self) -> Result<u64, ParserError> {
55        self.has_n_remaining(8)?;
56        Ok(self.get_u64())
57    }
58
59    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ParserError> {
60        self.has_n_remaining(buf.len())?;
61        self.copy_to_slice(buf);
62        Ok(())
63    }
64
65    fn read_address(&mut self, afi: &Afi) -> io::Result<IpAddr> {
66        match afi {
67            Afi::Ipv4 => match self.read_ipv4_address() {
68                Ok(ip) => Ok(IpAddr::V4(ip)),
69                _ => Err(io::Error::other("Cannot parse IPv4 address")),
70            },
71            Afi::Ipv6 => match self.read_ipv6_address() {
72                Ok(ip) => Ok(IpAddr::V6(ip)),
73                _ => Err(io::Error::other("Cannot parse IPv6 address")),
74            },
75            Afi::LinkState => {
76                // Link-State doesn't use traditional IP addresses
77                // Use IPv4 zero address as placeholder
78                Ok(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)))
79            }
80        }
81    }
82
83    fn read_ipv4_address(&mut self) -> Result<Ipv4Addr, ParserError> {
84        let addr = self.read_u32()?;
85        Ok(Ipv4Addr::from(addr))
86    }
87
88    fn read_ipv6_address(&mut self) -> Result<Ipv6Addr, ParserError> {
89        self.has_n_remaining(16)?;
90        let buf = self.get_u128();
91        Ok(Ipv6Addr::from(buf))
92    }
93
94    fn read_ipv4_prefix(&mut self) -> Result<Ipv4Net, ParserError> {
95        let addr = self.read_ipv4_address()?;
96        let mask = self.read_u8()?;
97        match Ipv4Net::new(addr, mask) {
98            Ok(n) => Ok(n),
99            Err(_) => Err(io::Error::other("Invalid prefix mask").into()),
100        }
101    }
102
103    fn read_ipv6_prefix(&mut self) -> Result<Ipv6Net, ParserError> {
104        let addr = self.read_ipv6_address()?;
105        let mask = self.read_u8()?;
106        match Ipv6Net::new(addr, mask) {
107            Ok(n) => Ok(n),
108            Err(_) => Err(io::Error::other("Invalid prefix mask").into()),
109        }
110    }
111
112    #[inline]
113    fn read_asn(&mut self, as_length: AsnLength) -> Result<Asn, ParserError> {
114        match as_length {
115            AsnLength::Bits16 => self.read_u16().map(Asn::new_16bit),
116            AsnLength::Bits32 => self.read_u32().map(Asn::new_32bit),
117        }
118    }
119
120    fn read_asns(&mut self, as_length: &AsnLength, count: usize) -> Result<Vec<Asn>, ParserError> {
121        let mut path = Vec::with_capacity(count);
122
123        match as_length {
124            AsnLength::Bits16 => {
125                self.has_n_remaining(count * 2)?; // 2 bytes for 16-bit ASN
126                for _ in 0..count {
127                    path.push(Asn::new_16bit(self.read_u16()?));
128                }
129            }
130            AsnLength::Bits32 => {
131                self.has_n_remaining(count * 4)?; // 4 bytes for 32-bit ASN
132                for _ in 0..count {
133                    path.push(Asn::new_32bit(self.read_u32()?));
134                }
135            }
136        }
137
138        Ok(path)
139    }
140
141    fn read_afi(&mut self) -> Result<Afi, ParserError> {
142        Afi::try_from(self.read_u16()?).map_err(ParserError::from)
143    }
144
145    fn read_safi(&mut self) -> Result<Safi, ParserError> {
146        Safi::try_from(self.read_u8()?).map_err(ParserError::from)
147    }
148
149    /// Read announced/withdrawn prefix.
150    ///
151    /// The length in bits is 1 byte, and then based on the IP version it reads different number of bytes.
152    /// If the `add_path` is true, it will also first read a 4-byte path id first; otherwise, a path-id of 0
153    /// is automatically set.
154    fn read_nlri_prefix(
155        &mut self,
156        afi: &Afi,
157        add_path: bool,
158    ) -> Result<NetworkPrefix, ParserError> {
159        let path_id = if add_path {
160            Some(self.read_u32()?)
161        } else {
162            None
163        };
164
165        // Length in bits
166        let bit_len = self.read_u8()?;
167
168        // Convert to bytes
169        let byte_len: usize = (bit_len as usize).div_ceil(8);
170        let addr: IpAddr = match afi {
171            Afi::Ipv4 => {
172                // 4 bytes -- u32
173                if byte_len > 4 {
174                    return Err(ParserError::ParseError(format!(
175                        "Invalid byte length for IPv4 prefix. byte_len: {byte_len}, bit_len: {bit_len}"
176                    )));
177                }
178                self.has_n_remaining(byte_len)?;
179                let mut buff = [0; 4];
180                self.copy_to_slice(&mut buff[..byte_len]);
181                IpAddr::V4(Ipv4Addr::from(buff))
182            }
183            Afi::Ipv6 => {
184                // 16 bytes
185                if byte_len > 16 {
186                    return Err(ParserError::ParseError(format!(
187                        "Invalid byte length for IPv6 prefix. byte_len: {byte_len}, bit_len: {bit_len}"
188                    )));
189                }
190                self.has_n_remaining(byte_len)?;
191                let mut buff = [0; 16];
192                self.copy_to_slice(&mut buff[..byte_len]);
193                IpAddr::V6(Ipv6Addr::from(buff))
194            }
195            Afi::LinkState => {
196                // Link-State doesn't use traditional IP prefixes
197                // Use IPv4 zero address as placeholder
198                IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))
199            }
200        };
201        let prefix = match IpNet::new(addr, bit_len) {
202            Ok(p) => p,
203            Err(_) => {
204                return Err(ParserError::ParseError(format!(
205                    "Invalid network prefix length: {bit_len}"
206                )))
207            }
208        };
209
210        Ok(NetworkPrefix::new(prefix, path_id))
211    }
212
213    fn read_n_bytes(&mut self, n_bytes: usize) -> Result<Vec<u8>, ParserError> {
214        self.has_n_remaining(n_bytes)?;
215        Ok(self.copy_to_bytes(n_bytes).into())
216    }
217
218    fn read_n_bytes_to_string(&mut self, n_bytes: usize) -> Result<String, ParserError> {
219        let buffer = self.read_n_bytes(n_bytes)?;
220        Ok(buffer
221            .into_iter()
222            .map(|x: u8| x as char)
223            .collect::<String>())
224    }
225}
226
227pub fn parse_nlri_list(
228    mut input: Bytes,
229    add_path: bool,
230    afi: &Afi,
231) -> Result<Vec<NetworkPrefix>, ParserError> {
232    let mut is_add_path = add_path;
233    let mut prefixes = vec![];
234
235    let mut retry = false;
236    let mut guessed = false;
237
238    let mut input_copy = None;
239
240    while input.remaining() > 0 {
241        if !is_add_path && input[0] == 0 {
242            // it's likely that this is a add-path wrongfully wrapped in non-add-path msg
243            debug!("not add-path but with NLRI size to be 0, likely add-path msg in wrong msg type, treat as add-path now");
244            // cloning the data bytes
245            is_add_path = true;
246            guessed = true;
247            input_copy = Some(input.clone());
248        }
249        let prefix = match input.read_nlri_prefix(afi, is_add_path) {
250            Ok(p) => p,
251            Err(e) => {
252                if guessed {
253                    retry = true;
254                    break;
255                } else {
256                    return Err(e);
257                }
258            }
259        };
260        prefixes.push(prefix);
261    }
262
263    if retry {
264        prefixes.clear();
265        // try again without attempt to guess add-path
266        // if we reach here (retry==true), input_copy must be Some
267        let mut input_2 = input_copy.unwrap();
268        while input_2.remaining() > 0 {
269            let prefix = input_2.read_nlri_prefix(afi, add_path)?;
270            prefixes.push(prefix);
271        }
272    }
273
274    Ok(prefixes)
275}
276
277pub fn encode_asn(asn: &Asn, asn_len: &AsnLength) -> Bytes {
278    let mut bytes = BytesMut::new();
279    match asn_len {
280        AsnLength::Bits16 => bytes.put_u16(asn.into()),
281        AsnLength::Bits32 => {
282            bytes.put_u32(asn.into());
283        }
284    }
285    bytes.freeze()
286}
287
288pub fn encode_ipaddr(addr: &IpAddr) -> Vec<u8> {
289    match addr {
290        IpAddr::V4(addr) => addr.octets().to_vec(),
291        IpAddr::V6(addr) => addr.octets().to_vec(),
292    }
293}
294
295pub fn encode_nlri_prefixes(prefixes: &[NetworkPrefix]) -> Bytes {
296    let mut bytes = BytesMut::new();
297    for prefix in prefixes {
298        bytes.extend(prefix.encode());
299    }
300    bytes.freeze()
301}
302
303/// A CRC32 implementation that converts a string to a hex string.
304///
305/// CRC32 is a checksum algorithm that is used to verify the integrity of data. It is short in
306/// length and sufficient for generating unique file names based on remote URLs.
307pub fn crc32(input: &str) -> String {
308    let input_bytes = input.as_bytes();
309    let mut table = [0u32; 256];
310    let polynomial = 0xedb88320u32;
311
312    for i in 0..256 {
313        let mut crc = i as u32;
314        for _ in 0..8 {
315            if crc & 1 == 1 {
316                crc = (crc >> 1) ^ polynomial;
317            } else {
318                crc >>= 1;
319            }
320        }
321        table[i as usize] = crc;
322    }
323
324    let mut crc = !0u32;
325    for byte in input_bytes.iter() {
326        let index = ((crc ^ (*byte as u32)) & 0xff) as usize;
327        crc = (crc >> 8) ^ table[index];
328    }
329
330    format!("{:08x}", !crc)
331}
332
333/// Convert a f64 timestamp into u32 seconds and u32 microseconds.
334///
335/// # Arguments
336///
337/// * `timestamp` - The timestamp to convert.
338///
339/// # Returns
340///
341/// A tuple containing the converted seconds and microseconds.
342///
343/// # Example
344///
345/// ```rust
346/// use bgpkit_parser::utils::convert_timestamp;
347///
348/// let timestamp = 1609459200.123456;
349/// let (seconds, microseconds) = convert_timestamp(timestamp);
350/// assert_eq!(seconds, 1609459200);
351/// assert_eq!(microseconds, 123456);
352/// ```
353// convert f64 timestamp into u32 seconds and u32 microseconds
354pub fn convert_timestamp(timestamp: f64) -> (u32, u32) {
355    let seconds = timestamp as u32;
356    let microseconds = ((timestamp - seconds as f64) * 1_000_000.0) as u32;
357    (seconds, microseconds)
358}
359
360#[derive(Debug, Clone)]
361pub struct ComparableRegex {
362    pattern: String,
363    regex: Regex,
364}
365
366impl PartialEq for ComparableRegex {
367    fn eq(&self, other: &Self) -> bool {
368        self.pattern == other.pattern
369    }
370}
371
372impl ComparableRegex {
373    pub fn new(pattern: &str) -> Result<Self, ParserError> {
374        let regex = match Regex::new(pattern) {
375            Ok(r) => r,
376            Err(_) => {
377                return Err(ParserError::FilterError(format!(
378                    "Invalid regex pattern: {pattern}"
379                )))
380            }
381        };
382        Ok(ComparableRegex {
383            pattern: pattern.to_string(),
384            regex,
385        })
386    }
387
388    pub fn is_match<S: AsRef<str>>(&self, text: S) -> bool {
389        self.regex.is_match(text.as_ref())
390    }
391}
392
393#[cfg(test)]
394mod tests {
395    use super::*;
396    use bytes::Bytes;
397
398    #[test]
399    fn test_read_u8() {
400        let mut buf = Bytes::from_static(&[0x12]);
401        assert_eq!(buf.read_u8().unwrap(), 0x12);
402    }
403
404    #[test]
405    fn test_read_u16() {
406        let mut buf = Bytes::from_static(&[0x12, 0x34]);
407        assert_eq!(buf.read_u16().unwrap(), 0x1234);
408    }
409
410    #[test]
411    fn test_read_u32() {
412        let mut buf = Bytes::from_static(&[0x12, 0x34, 0x56, 0x78]);
413        assert_eq!(buf.read_u32().unwrap(), 0x12345678);
414    }
415
416    #[test]
417    fn test_read_u64() {
418        let mut buf = Bytes::from_static(&[0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]);
419        assert_eq!(buf.read_u64().unwrap(), 0x123456789ABCDEF0);
420    }
421
422    #[test]
423    fn test_read_ipv4_address() {
424        let mut buf = Bytes::from_static(&[0xC0, 0xA8, 0x01, 0x01]);
425        assert_eq!(
426            buf.read_ipv4_address().unwrap(),
427            Ipv4Addr::new(192, 168, 1, 1)
428        );
429    }
430
431    #[test]
432    fn test_read_ipv6_address() {
433        let mut buf = Bytes::from_static(&[
434            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
435            0x73, 0x34,
436        ]);
437        assert_eq!(
438            buf.read_ipv6_address().unwrap(),
439            Ipv6Addr::new(0x2001, 0x0DB8, 0x85A3, 0x0000, 0x0000, 0x8A2E, 0x0370, 0x7334)
440        );
441    }
442
443    #[test]
444    fn test_read_address() {
445        let mut buf = Bytes::from_static(&[0xC0, 0xA8, 0x01, 0x01]);
446        assert_eq!(
447            buf.read_address(&Afi::Ipv4).unwrap(),
448            IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))
449        );
450
451        let mut buf = Bytes::from_static(&[
452            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
453            0x73, 0x34,
454        ]);
455        assert_eq!(
456            buf.read_address(&Afi::Ipv6).unwrap(),
457            IpAddr::V6(Ipv6Addr::new(
458                0x2001, 0x0DB8, 0x85A3, 0x0000, 0x0000, 0x8A2E, 0x0370, 0x7334
459            ))
460        );
461
462        let mut buf = Bytes::from_static(&[0xC0, 0xA8, 0x01]);
463        assert!(buf.read_address(&Afi::Ipv4).is_err());
464
465        let mut buf = Bytes::from_static(&[
466            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
467            0x73,
468        ]);
469        assert!(buf.read_address(&Afi::Ipv6).is_err());
470    }
471
472    #[test]
473    fn test_read_asn() {
474        let mut buf = Bytes::from_static(&[0x00, 0x01]);
475        assert_eq!(buf.read_asn(AsnLength::Bits16).unwrap(), Asn::new_16bit(1));
476
477        let mut buf = Bytes::from_static(&[0x00, 0x00, 0x01, 0x00]);
478        assert_eq!(
479            buf.read_asn(AsnLength::Bits32).unwrap(),
480            Asn::new_32bit(256)
481        );
482    }
483
484    #[test]
485    fn read_asns() {
486        let mut buf = Bytes::from_static(&[0x00, 0x01, 0x00, 0x00]);
487        assert_eq!(
488            buf.read_asns(&AsnLength::Bits16, 2).unwrap(),
489            vec![Asn::new_16bit(1), Asn::new_16bit(0)]
490        );
491    }
492
493    #[test]
494    fn test_read_afi() {
495        let mut buf = Bytes::from_static(&[0x00, 0x01]);
496        assert_eq!(buf.read_afi().unwrap(), Afi::Ipv4);
497
498        let mut buf = Bytes::from_static(&[0x00, 0x02]);
499        assert_eq!(buf.read_afi().unwrap(), Afi::Ipv6);
500    }
501
502    #[test]
503    fn test_read_safi() {
504        let mut buf = Bytes::from_static(&[0x01]);
505        assert_eq!(buf.read_safi().unwrap(), Safi::Unicast);
506
507        let mut buf = Bytes::from_static(&[0x02]);
508        assert_eq!(buf.read_safi().unwrap(), Safi::Multicast);
509
510        // RFC 8950 VPN SAFI values
511        let mut buf = Bytes::from_static(&[0x80]); // 128 in hex
512        assert_eq!(buf.read_safi().unwrap(), Safi::MplsVpn);
513
514        let mut buf = Bytes::from_static(&[0x81]); // 129 in hex
515        assert_eq!(buf.read_safi().unwrap(), Safi::MulticastVpn);
516    }
517
518    #[test]
519    fn test_has_n_remaining() {
520        let mut buf = Bytes::from_static(&[0x12, 0x34, 0x56, 0x78]);
521        assert!(buf.has_n_remaining(4).is_ok());
522        assert!(buf.has_n_remaining(5).is_err());
523
524        let _ = buf.read_u8().unwrap();
525        assert!(buf.has_n_remaining(3).is_ok());
526        assert!(buf.has_n_remaining(4).is_err());
527    }
528
529    #[test]
530    fn test_read_ipv4_prefix() {
531        let mut buf = Bytes::from_static(&[0xC0, 0xA8, 0x01, 0x01, 0x18]);
532        assert_eq!(
533            buf.read_ipv4_prefix().unwrap(),
534            Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 1), 24).unwrap()
535        );
536
537        // Test with invalid IPv4 prefix mask, /33
538        let mut buf = Bytes::from_static(&[0xC0, 0xA8, 0x01, 0x01, 0x21]);
539        assert!(buf.read_ipv4_prefix().is_err());
540    }
541
542    #[test]
543    fn test_read_ipv6_prefix() {
544        let mut buf = Bytes::from_static(&[
545            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
546            0x73, 0x34, 0x40,
547        ]);
548        assert_eq!(
549            buf.read_ipv6_prefix().unwrap(),
550            Ipv6Net::new(
551                Ipv6Addr::new(0x2001, 0x0DB8, 0x85A3, 0x0000, 0x0000, 0x8A2E, 0x0370, 0x7334),
552                64
553            )
554            .unwrap()
555        );
556
557        // Test with invalid IPv6 prefix mask, /129
558        let mut buf = Bytes::from_static(&[
559            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
560            0x73, 0x34, 0x81,
561        ]);
562        assert!(buf.read_ipv6_prefix().is_err());
563    }
564
565    #[test]
566    fn test_read_n_bytes() {
567        let mut buf = Bytes::from_static(&[0x12, 0x34, 0x56, 0x78]);
568        assert_eq!(buf.read_n_bytes(4).unwrap(), vec![0x12, 0x34, 0x56, 0x78]);
569    }
570
571    #[test]
572    fn test_read_n_bytes_to_string() {
573        let mut buf = Bytes::from_static(&[0x48, 0x65, 0x6C, 0x6C, 0x6F]); // "Hello" in ASCII
574        assert_eq!(buf.read_n_bytes_to_string(5).unwrap(), "Hello");
575    }
576
577    #[test]
578    fn test_crc32() {
579        assert_eq!(crc32("Hello, World!"), "ec4ac3d0");
580    }
581
582    #[test]
583    fn test_read_nlri_prefix() {
584        let mut buf = Bytes::from_static(&[0x18, 0xC0, 0xA8, 0x01]);
585        let expected = NetworkPrefix::new(
586            IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
587            None,
588        );
589        assert_eq!(buf.read_nlri_prefix(&Afi::Ipv4, false).unwrap(), expected);
590
591        let mut buf = Bytes::from_static(&[0x00, 0x00, 0x00, 0x01, 0x18, 0xC0, 0xA8, 0x01]);
592        let expected = NetworkPrefix::new(
593            IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
594            Some(1),
595        );
596        assert_eq!(buf.read_nlri_prefix(&Afi::Ipv4, true).unwrap(), expected);
597    }
598
599    #[test]
600    fn test_encode_asn() {
601        let asn = Asn::new_32bit(1);
602        let asn_len = AsnLength::Bits32;
603        let expected = Bytes::from_static(&[0x00, 0x00, 0x00, 0x01]);
604        assert_eq!(encode_asn(&asn, &asn_len), expected);
605
606        let asn = Asn::new_16bit(1);
607        let asn_len = AsnLength::Bits16;
608        let expected = Bytes::from_static(&[0x00, 0x01]);
609        assert_eq!(encode_asn(&asn, &asn_len), expected);
610    }
611
612    #[test]
613    fn test_encode_ipaddr() {
614        let addr = IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1));
615        let expected = vec![192, 168, 1, 1];
616        assert_eq!(encode_ipaddr(&addr), expected);
617
618        let addr = IpAddr::V6(Ipv6Addr::new(
619            0x2001, 0x0DB8, 0x85A3, 0x0000, 0x0000, 0x8A2E, 0x0370, 0x7334,
620        ));
621        let expected = vec![
622            0x20, 0x01, 0x0D, 0xB8, 0x85, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x2E, 0x03, 0x70,
623            0x73, 0x34,
624        ];
625        assert_eq!(encode_ipaddr(&addr), expected);
626    }
627
628    #[test]
629    fn test_encode_nlri_prefixes() {
630        let prefixes = vec![
631            NetworkPrefix::new(
632                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
633                None,
634            ),
635            NetworkPrefix::new(
636                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()),
637                None,
638            ),
639        ];
640        let expected = Bytes::from_static(&[0x18, 0xC0, 0xA8, 0x01, 0x18, 0xC0, 0xA8, 0x02]);
641        assert_eq!(encode_nlri_prefixes(&prefixes), expected);
642
643        let prefixes = vec![
644            NetworkPrefix::new(
645                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
646                Some(1),
647            ),
648            NetworkPrefix::new(
649                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()),
650                Some(1),
651            ),
652        ];
653        let expected = Bytes::from_static(&[
654            0x00, 0x00, 0x00, 0x01, 0x18, 0xC0, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x01, 0x18, 0xC0,
655            0xA8, 0x02,
656        ]);
657        assert_eq!(encode_nlri_prefixes(&prefixes), expected);
658    }
659
660    #[test]
661    fn test_comparable_regex_functionality() {
662        // Test valid pattern creation
663        let regex1 = ComparableRegex::new(r"\d+").unwrap();
664        let regex2 = ComparableRegex::new(r"\d+").unwrap();
665        let regex3 = ComparableRegex::new(r"\w+").unwrap();
666
667        // Verify pattern storage
668        assert_eq!(regex1.pattern, r"\d+");
669        assert_eq!(regex3.pattern, r"\w+");
670
671        // Verify equality with same pattern
672        assert_eq!(regex1, regex2);
673
674        // Verify inequality with different patterns
675        assert_ne!(regex1, regex3);
676
677        // Verify regex matching functionality
678        assert!(regex1.regex.is_match("123"));
679        assert!(!regex1.regex.is_match("abc"));
680    }
681
682    #[test]
683    #[should_panic(expected = "Invalid regex pattern")]
684    fn test_comparable_regex_invalid_pattern_panic() {
685        // Test invalid pattern creation
686        ComparableRegex::new(r"(\d+").unwrap(); // Unclosed parenthesis should panic
687    }
688
689    #[test]
690    fn test_parse_nlri_list() {
691        // Test normal case with add_path=false
692        let input = Bytes::from_static(&[0x18, 0xC0, 0xA8, 0x01, 0x18, 0xC0, 0xA8, 0x02]);
693        let expected = vec![
694            NetworkPrefix::new(
695                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
696                None,
697            ),
698            NetworkPrefix::new(
699                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()),
700                None,
701            ),
702        ];
703        assert_eq!(parse_nlri_list(input, false, &Afi::Ipv4).unwrap(), expected);
704
705        // Test normal case with add_path=true
706        let input = Bytes::from_static(&[
707            0x00, 0x00, 0x00, 0x01, 0x18, 0xC0, 0xA8, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0xC0,
708            0xA8, 0x02,
709        ]);
710        let expected = vec![
711            NetworkPrefix::new(
712                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
713                Some(1),
714            ),
715            NetworkPrefix::new(
716                IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 2, 0), 24).unwrap()),
717                Some(2),
718            ),
719        ];
720        assert_eq!(parse_nlri_list(input, true, &Afi::Ipv4).unwrap(), expected);
721
722        // Test the auto-detection of add_path when first byte is 0
723        let input = Bytes::from_static(&[0x00, 0x00, 0x00, 0x01, 0x18, 0xC0, 0xA8, 0x01]);
724        let expected = vec![NetworkPrefix::new(
725            IpNet::V4(Ipv4Net::new(Ipv4Addr::new(192, 168, 1, 0), 24).unwrap()),
726            Some(1),
727        )];
728        assert_eq!(parse_nlri_list(input, false, &Afi::Ipv4).unwrap(), expected);
729    }
730
731    #[test]
732    fn test_convert_timestamp() {
733        // Test integer timestamp
734        let (seconds, microseconds) = convert_timestamp(1609459200.0);
735        assert_eq!(seconds, 1609459200);
736        assert_eq!(microseconds, 0);
737
738        // Test fractional timestamp
739        let (seconds, microseconds) = convert_timestamp(1609459200.123456);
740        assert_eq!(seconds, 1609459200);
741        assert_eq!(microseconds, 123456);
742
743        // Test rounding
744        let (seconds, microseconds) = convert_timestamp(1609459200.1234567);
745        assert_eq!(seconds, 1609459200);
746        assert_eq!(microseconds, 123456); // Should round to microseconds
747    }
748}