bgpkit_parser/models/bgp/
capabilities.rs

1use crate::error::ParserError;
2use crate::models::network::{Afi, Safi};
3#[cfg(feature = "parser")]
4use crate::parser::ReadUtils;
5#[cfg(feature = "parser")]
6use bytes::{BufMut, Bytes, BytesMut};
7use num_enum::{FromPrimitive, IntoPrimitive};
8
9#[allow(non_camel_case_types)]
10#[derive(Debug, FromPrimitive, IntoPrimitive, PartialEq, Eq, Hash, Copy, Clone)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12#[repr(u8)]
13pub enum BgpCapabilityType {
14    MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4 = 1,
15    ROUTE_REFRESH_CAPABILITY_FOR_BGP_4 = 2,
16    OUTBOUND_ROUTE_FILTERING_CAPABILITY = 3,
17    EXTENDED_NEXT_HOP_ENCODING = 5,
18    BGP_EXTENDED_MESSAGE = 6,
19    BGPSEC_CAPABILITY = 7,
20    MULTIPLE_LABELS_CAPABILITY = 8,
21    BGP_ROLE = 9,
22    GRACEFUL_RESTART_CAPABILITY = 64,
23    SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY = 65,
24    SUPPORT_FOR_DYNAMIC_CAPABILITY = 67,
25    MULTISESSION_BGP_CAPABILITY = 68,
26    ADD_PATH_CAPABILITY = 69,
27    ENHANCED_ROUTE_REFRESH_CAPABILITY = 70,
28    LONG_LIVED_GRACEFUL_RESTART_CAPABILITY = 71,
29    ROUTING_POLICY_DISTRIBUTION = 72,
30    FQDN_CAPABILITY = 73,
31
32    /// Catch-all type for any deprecated, unassigned, or reserved codes
33    #[num_enum(catch_all)]
34    Unknown(u8),
35}
36
37impl BgpCapabilityType {
38    pub const fn is_deprecated(&self) -> bool {
39        matches!(
40            self,
41            BgpCapabilityType::Unknown(4 | 66 | 128 | 129 | 130 | 131 | 184 | 185)
42        )
43    }
44
45    pub const fn is_reserved(&self) -> bool {
46        matches!(self, BgpCapabilityType::Unknown(0 | 255))
47    }
48
49    pub const fn is_reserved_for_experimental_use(&self) -> bool {
50        matches!(self, BgpCapabilityType::Unknown(239..=254))
51    }
52}
53
54/// Extended Next Hop capability entry - RFC 8950, Section 3
55/// Represents a single <NLRI AFI, NLRI SAFI, NextHop AFI> triple
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
58pub struct ExtendedNextHopEntry {
59    /// Address Family Identifier for NLRI (typically AFI=1 for IPv4)
60    pub nlri_afi: Afi,
61    /// Subsequent Address Family Identifier for NLRI (1, 2, 4, 128, 129 per RFC 8950)
62    pub nlri_safi: Safi,
63    /// Address Family Identifier for Next Hop (typically AFI=2 for IPv6)  
64    pub nexthop_afi: Afi,
65}
66
67/// Extended Next Hop capability - RFC 8950, Section 3
68/// Contains a list of supported NLRI/NextHop AFI/SAFI combinations
69#[derive(Debug, Clone, PartialEq, Eq)]
70#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
71pub struct ExtendedNextHopCapability {
72    /// List of supported AFI/SAFI combinations for extended next hop encoding
73    pub entries: Vec<ExtendedNextHopEntry>,
74}
75
76impl ExtendedNextHopCapability {
77    /// Create a new Extended Next Hop capability with the given entries
78    pub fn new(entries: Vec<ExtendedNextHopEntry>) -> Self {
79        Self { entries }
80    }
81
82    /// Check if this capability supports a specific NLRI AFI/SAFI with NextHop AFI combination
83    pub fn supports(&self, nlri_afi: Afi, nlri_safi: Safi, nexthop_afi: Afi) -> bool {
84        self.entries.iter().any(|entry| {
85            entry.nlri_afi == nlri_afi
86                && entry.nlri_safi == nlri_safi
87                && entry.nexthop_afi == nexthop_afi
88        })
89    }
90
91    /// Get all supported NLRI AFI/SAFI combinations for a given NextHop AFI
92    pub fn supported_nlri_for_nexthop(&self, nexthop_afi: Afi) -> Vec<(Afi, Safi)> {
93        self.entries
94            .iter()
95            .filter(|entry| entry.nexthop_afi == nexthop_afi)
96            .map(|entry| (entry.nlri_afi, entry.nlri_safi))
97            .collect()
98    }
99
100    /// Parse Extended Next Hop capability from raw bytes - RFC 8950, Section 3
101    ///
102    /// Format: Series of 6-byte entries, each containing:
103    /// - NLRI AFI (2 bytes)
104    /// - NLRI SAFI (2 bytes)
105    /// - NextHop AFI (2 bytes)
106    #[cfg(feature = "parser")]
107    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
108        let mut entries = Vec::new();
109
110        // Each entry is 6 bytes (2 + 2 + 2)
111        if !data.len().is_multiple_of(6) {
112            return Err(ParserError::ParseError(format!(
113                "Extended Next Hop capability length {} is not divisible by 6",
114                data.len()
115            )));
116        }
117
118        while data.len() >= 6 {
119            let nlri_afi = data.read_afi()?;
120            // SAFI is encoded as 2 bytes in capability, but SAFI enum is u8
121            let nlri_safi_u16 = data.read_u16()?;
122            let nlri_safi = Safi::try_from(nlri_safi_u16 as u8).map_err(|_| {
123                ParserError::ParseError(format!("Unknown SAFI type: {}", nlri_safi_u16))
124            })?;
125            let nexthop_afi = data.read_afi()?;
126
127            entries.push(ExtendedNextHopEntry {
128                nlri_afi,
129                nlri_safi,
130                nexthop_afi,
131            });
132        }
133
134        Ok(ExtendedNextHopCapability::new(entries))
135    }
136
137    /// Encode Extended Next Hop capability to raw bytes - RFC 8950, Section 3
138    #[cfg(feature = "parser")]
139    pub fn encode(&self) -> Bytes {
140        let mut bytes = BytesMut::with_capacity(self.entries.len() * 6);
141
142        for entry in &self.entries {
143            bytes.put_u16(entry.nlri_afi as u16); // NLRI AFI (2 bytes)
144            bytes.put_u16(entry.nlri_safi as u8 as u16); // NLRI SAFI (2 bytes in capability, but SAFI is u8)
145            bytes.put_u16(entry.nexthop_afi as u16); // NextHop AFI (2 bytes)
146        }
147
148        bytes.freeze()
149    }
150}
151
152/// Multiprotocol Extensions capability entry - RFC 2858, Section 7
153/// Represents a single <AFI, SAFI> combination
154#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
156pub struct MultiprotocolExtensionsCapability {
157    /// Address Family Identifier
158    pub afi: Afi,
159    /// Subsequent Address Family Identifier
160    pub safi: Safi,
161}
162
163impl MultiprotocolExtensionsCapability {
164    /// Create a new Multiprotocol Extensions capability
165    pub fn new(afi: Afi, safi: Safi) -> Self {
166        Self { afi, safi }
167    }
168
169    /// Parse Multiprotocol Extensions capability from raw bytes - RFC 2858, Section 7
170    ///
171    /// Format: 4 bytes total
172    /// - AFI (2 bytes)
173    /// - Reserved (1 byte) - should be 0
174    /// - SAFI (1 byte)
175    #[cfg(feature = "parser")]
176    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
177        if data.len() != 4 {
178            return Err(ParserError::ParseError(format!(
179                "Multiprotocol Extensions capability length {} is not 4",
180                data.len()
181            )));
182        }
183
184        let afi = data.read_afi()?;
185        let _reserved = data.read_u8()?; // Reserved field, should be 0 but ignored
186        let safi_u8 = data.read_u8()?;
187        let safi = Safi::try_from(safi_u8)
188            .map_err(|_| ParserError::ParseError(format!("Unknown SAFI type: {}", safi_u8)))?;
189
190        Ok(MultiprotocolExtensionsCapability::new(afi, safi))
191    }
192
193    /// Encode Multiprotocol Extensions capability to raw bytes - RFC 2858, Section 7
194    #[cfg(feature = "parser")]
195    pub fn encode(&self) -> Bytes {
196        let mut bytes = BytesMut::with_capacity(4);
197        bytes.put_u16(self.afi as u16); // AFI (2 bytes)
198        bytes.put_u8(0); // Reserved (1 byte) - set to 0
199        bytes.put_u8(self.safi as u8); // SAFI (1 byte)
200        bytes.freeze()
201    }
202}
203
204/// Graceful Restart capability - RFC 4724
205#[derive(Debug, Clone, PartialEq, Eq)]
206#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
207pub struct GracefulRestartCapability {
208    /// Restart state flag - indicates BGP speaker has restarted
209    pub restart_state: bool,
210    /// Restart time in seconds
211    pub restart_time: u16,
212    /// List of address families that support Graceful Restart
213    pub address_families: Vec<GracefulRestartAddressFamily>,
214}
215
216/// Address family entry for Graceful Restart capability - RFC 4724
217#[derive(Debug, Clone, PartialEq, Eq, Hash)]
218#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
219pub struct GracefulRestartAddressFamily {
220    /// Address Family Identifier
221    pub afi: Afi,
222    /// Subsequent Address Family Identifier
223    pub safi: Safi,
224    /// Forwarding state preserved flag
225    pub forwarding_state: bool,
226}
227
228impl GracefulRestartCapability {
229    /// Create a new Graceful Restart capability
230    pub fn new(
231        restart_state: bool,
232        restart_time: u16,
233        address_families: Vec<GracefulRestartAddressFamily>,
234    ) -> Self {
235        Self {
236            restart_state,
237            restart_time,
238            address_families,
239        }
240    }
241
242    /// Parse Graceful Restart capability from raw bytes - RFC 4724
243    ///
244    /// Format:
245    /// - Restart Flags (4 bits) + Restart Time (12 bits) = 2 bytes total
246    /// - Followed by 0 or more address family entries (4 bytes each)
247    #[cfg(feature = "parser")]
248    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
249        if data.len() < 2 {
250            return Err(ParserError::ParseError(format!(
251                "Graceful Restart capability length {} is less than minimum 2 bytes",
252                data.len()
253            )));
254        }
255
256        // Parse restart flags and time (16 bits total)
257        let restart_flags_and_time = data.read_u16()?;
258        let restart_state = (restart_flags_and_time & 0x8000) != 0; // Most significant bit
259        let restart_time = restart_flags_and_time & 0x0FFF; // Lower 12 bits
260
261        let mut address_families = Vec::new();
262
263        // Parse address family entries (4 bytes each)
264        if !data.len().is_multiple_of(4) {
265            return Err(ParserError::ParseError(format!(
266                "Graceful Restart capability remaining length {} is not divisible by 4",
267                data.len()
268            )));
269        }
270
271        while data.len() >= 4 {
272            let afi = data.read_afi()?;
273            let safi_u8 = data.read_u8()?;
274            let safi = Safi::try_from(safi_u8)
275                .map_err(|_| ParserError::ParseError(format!("Unknown SAFI type: {}", safi_u8)))?;
276            let flags = data.read_u8()?;
277            let forwarding_state = (flags & 0x80) != 0; // Most significant bit
278
279            address_families.push(GracefulRestartAddressFamily {
280                afi,
281                safi,
282                forwarding_state,
283            });
284        }
285
286        Ok(GracefulRestartCapability::new(
287            restart_state,
288            restart_time,
289            address_families,
290        ))
291    }
292
293    /// Encode Graceful Restart capability to raw bytes - RFC 4724
294    #[cfg(feature = "parser")]
295    pub fn encode(&self) -> Bytes {
296        let mut bytes = BytesMut::with_capacity(2 + self.address_families.len() * 4);
297
298        // Encode restart flags and time
299        let restart_flags_and_time = if self.restart_state {
300            0x8000 | (self.restart_time & 0x0FFF)
301        } else {
302            self.restart_time & 0x0FFF
303        };
304        bytes.put_u16(restart_flags_and_time);
305
306        // Encode address family entries
307        for af in &self.address_families {
308            bytes.put_u16(af.afi as u16); // AFI (2 bytes)
309            bytes.put_u8(af.safi as u8); // SAFI (1 byte)
310            let flags = if af.forwarding_state { 0x80 } else { 0x00 };
311            bytes.put_u8(flags); // Flags (1 byte)
312        }
313
314        bytes.freeze()
315    }
316}
317
318/// ADD-PATH capability - RFC 7911
319#[derive(Debug, Clone, PartialEq, Eq)]
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321pub struct AddPathCapability {
322    /// List of address families and their send/receive modes
323    pub address_families: Vec<AddPathAddressFamily>,
324}
325
326/// Address family entry for ADD-PATH capability - RFC 7911
327#[derive(Debug, Clone, PartialEq, Eq, Hash)]
328#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
329pub struct AddPathAddressFamily {
330    /// Address Family Identifier
331    pub afi: Afi,
332    /// Subsequent Address Family Identifier
333    pub safi: Safi,
334    /// Send/Receive mode
335    pub send_receive: AddPathSendReceive,
336}
337
338/// Send/Receive mode for ADD-PATH capability - RFC 7911
339#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
340#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
341pub enum AddPathSendReceive {
342    /// Can receive multiple paths (value 1)
343    Receive = 1,
344    /// Can send multiple paths (value 2)
345    Send = 2,
346    /// Can both send and receive multiple paths (value 3)
347    SendReceive = 3,
348}
349
350impl TryFrom<u8> for AddPathSendReceive {
351    type Error = ParserError;
352
353    fn try_from(value: u8) -> Result<Self, Self::Error> {
354        match value {
355            1 => Ok(AddPathSendReceive::Receive),
356            2 => Ok(AddPathSendReceive::Send),
357            3 => Ok(AddPathSendReceive::SendReceive),
358            _ => Err(ParserError::ParseError(format!(
359                "Invalid ADD-PATH Send/Receive value: {}",
360                value
361            ))),
362        }
363    }
364}
365
366impl AddPathCapability {
367    /// Create a new ADD-PATH capability
368    pub fn new(address_families: Vec<AddPathAddressFamily>) -> Self {
369        Self { address_families }
370    }
371
372    /// Parse ADD-PATH capability from raw bytes - RFC 7911
373    ///
374    /// Format: Series of 4-byte entries, each containing:
375    /// - AFI (2 bytes)
376    /// - SAFI (1 byte)
377    /// - Send/Receive (1 byte)
378    #[cfg(feature = "parser")]
379    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
380        let mut address_families = Vec::new();
381
382        // Each entry is 4 bytes (2 + 1 + 1)
383        if !data.len().is_multiple_of(4) {
384            return Err(ParserError::ParseError(format!(
385                "ADD-PATH capability length {} is not divisible by 4",
386                data.len()
387            )));
388        }
389
390        while data.len() >= 4 {
391            let afi = data.read_afi()?;
392            let safi_u8 = data.read_u8()?;
393            let safi = Safi::try_from(safi_u8)
394                .map_err(|_| ParserError::ParseError(format!("Unknown SAFI type: {}", safi_u8)))?;
395            let send_receive_u8 = data.read_u8()?;
396            let send_receive = AddPathSendReceive::try_from(send_receive_u8)?;
397
398            address_families.push(AddPathAddressFamily {
399                afi,
400                safi,
401                send_receive,
402            });
403        }
404
405        Ok(AddPathCapability::new(address_families))
406    }
407
408    /// Encode ADD-PATH capability to raw bytes - RFC 7911
409    #[cfg(feature = "parser")]
410    pub fn encode(&self) -> Bytes {
411        let mut bytes = BytesMut::with_capacity(self.address_families.len() * 4);
412
413        for af in &self.address_families {
414            bytes.put_u16(af.afi as u16); // AFI (2 bytes)
415            bytes.put_u8(af.safi as u8); // SAFI (1 byte)
416            bytes.put_u8(af.send_receive as u8); // Send/Receive (1 byte)
417        }
418
419        bytes.freeze()
420    }
421}
422
423/// Route Refresh capability - RFC 2918
424/// This capability has no parameters, it's just a flag indicating support
425#[derive(Debug, Clone, PartialEq, Eq, Hash)]
426#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
427pub struct RouteRefreshCapability;
428
429impl RouteRefreshCapability {
430    /// Create a new Route Refresh capability
431    pub fn new() -> Self {
432        Self
433    }
434
435    /// Parse Route Refresh capability from raw bytes - RFC 2918
436    /// This capability has length 0, so data should be empty
437    #[cfg(feature = "parser")]
438    pub fn parse(data: Bytes) -> Result<Self, ParserError> {
439        if !data.is_empty() {
440            return Err(ParserError::ParseError(format!(
441                "Route Refresh capability should have length 0, got {}",
442                data.len()
443            )));
444        }
445        Ok(RouteRefreshCapability::new())
446    }
447
448    /// Encode Route Refresh capability to raw bytes - RFC 2918
449    /// Always returns empty bytes since this capability has no parameters
450    #[cfg(feature = "parser")]
451    pub fn encode(&self) -> Bytes {
452        Bytes::new()
453    }
454}
455
456impl Default for RouteRefreshCapability {
457    fn default() -> Self {
458        Self::new()
459    }
460}
461
462/// BGP Extended Message capability - RFC 8654
463/// This capability has no parameters, it's just a flag indicating support for extended messages
464#[derive(Debug, Clone, PartialEq, Eq, Hash)]
465#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
466pub struct BgpExtendedMessageCapability;
467
468impl BgpExtendedMessageCapability {
469    /// Create a new BGP Extended Message capability
470    pub fn new() -> Self {
471        Self
472    }
473
474    /// Parse BGP Extended Message capability from raw bytes - RFC 8654
475    /// This capability has length 0, so data should be empty
476    #[cfg(feature = "parser")]
477    pub fn parse(data: Bytes) -> Result<Self, ParserError> {
478        if !data.is_empty() {
479            return Err(ParserError::ParseError(format!(
480                "BGP Extended Message capability should have length 0, got {}",
481                data.len()
482            )));
483        }
484        Ok(BgpExtendedMessageCapability::new())
485    }
486
487    /// Encode BGP Extended Message capability to raw bytes - RFC 8654
488    /// Always returns empty bytes since this capability has no parameters
489    #[cfg(feature = "parser")]
490    pub fn encode(&self) -> Bytes {
491        Bytes::new()
492    }
493}
494
495impl Default for BgpExtendedMessageCapability {
496    fn default() -> Self {
497        Self::new()
498    }
499}
500
501/// 4-octet AS number capability - RFC 6793
502#[derive(Debug, Clone, PartialEq, Eq, Hash)]
503#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
504pub struct FourOctetAsCapability {
505    /// The 4-octet AS number of the BGP speaker
506    pub asn: u32,
507}
508
509impl FourOctetAsCapability {
510    /// Create a new 4-octet AS capability
511    pub fn new(asn: u32) -> Self {
512        Self { asn }
513    }
514
515    /// Parse 4-octet AS capability from raw bytes - RFC 6793
516    /// Format: 4 bytes containing the AS number
517    #[cfg(feature = "parser")]
518    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
519        if data.len() != 4 {
520            return Err(ParserError::ParseError(format!(
521                "4-octet AS capability length {} is not 4",
522                data.len()
523            )));
524        }
525
526        let asn = data.read_u32()?;
527        Ok(FourOctetAsCapability::new(asn))
528    }
529
530    /// Encode 4-octet AS capability to raw bytes - RFC 6793
531    #[cfg(feature = "parser")]
532    pub fn encode(&self) -> Bytes {
533        let mut bytes = BytesMut::with_capacity(4);
534        bytes.put_u32(self.asn);
535        bytes.freeze()
536    }
537}
538
539/// BGP Role capability - RFC 9234
540#[derive(Debug, Clone, PartialEq, Eq, Hash)]
541#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
542pub struct BgpRoleCapability {
543    /// The BGP Role of this speaker
544    pub role: BgpRole,
545}
546
547/// BGP Role values - RFC 9234, Section 4.1
548#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
549#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
550pub enum BgpRole {
551    /// Provider (value 0)
552    Provider = 0,
553    /// Route Server (value 1)
554    RouteServer = 1,
555    /// Route Server Client (value 2)
556    RouteServerClient = 2,
557    /// Customer (value 3)
558    Customer = 3,
559    /// Peer (Lateral Peer) (value 4)
560    Peer = 4,
561}
562
563impl TryFrom<u8> for BgpRole {
564    type Error = ParserError;
565
566    fn try_from(value: u8) -> Result<Self, Self::Error> {
567        match value {
568            0 => Ok(BgpRole::Provider),
569            1 => Ok(BgpRole::RouteServer),
570            2 => Ok(BgpRole::RouteServerClient),
571            3 => Ok(BgpRole::Customer),
572            4 => Ok(BgpRole::Peer),
573            _ => Err(ParserError::ParseError(format!(
574                "Unknown BGP Role value: {}",
575                value
576            ))),
577        }
578    }
579}
580
581impl BgpRoleCapability {
582    /// Create a new BGP Role capability
583    pub fn new(role: BgpRole) -> Self {
584        Self { role }
585    }
586
587    /// Parse BGP Role capability from raw bytes - RFC 9234
588    /// Format: 1 byte containing the role value
589    #[cfg(feature = "parser")]
590    pub fn parse(mut data: Bytes) -> Result<Self, ParserError> {
591        if data.len() != 1 {
592            return Err(ParserError::ParseError(format!(
593                "BGP Role capability length {} is not 1",
594                data.len()
595            )));
596        }
597
598        let role_u8 = data.read_u8()?;
599        let role = BgpRole::try_from(role_u8)?;
600        Ok(BgpRoleCapability::new(role))
601    }
602
603    /// Encode BGP Role capability to raw bytes - RFC 9234
604    #[cfg(feature = "parser")]
605    pub fn encode(&self) -> Bytes {
606        let mut bytes = BytesMut::with_capacity(1);
607        bytes.put_u8(self.role as u8);
608        bytes.freeze()
609    }
610}
611
612#[cfg(all(test, feature = "parser"))]
613mod tests {
614    use super::*;
615
616    #[test]
617    fn test_parsing_capability() {
618        // reserved
619        assert!(BgpCapabilityType::from(0).is_reserved());
620        assert!(BgpCapabilityType::from(255).is_reserved());
621
622        // deprecated
623        for code in [4, 66, 128, 129, 130, 131, 184, 185] {
624            assert!(BgpCapabilityType::from(code).is_deprecated());
625        }
626
627        // unassigned
628        let unassigned_ranges = [10..=63, 74..=127, 132..=183, 186..=238];
629        for code in <[_; 4]>::into_iter(unassigned_ranges).flatten() {
630            let ty = BgpCapabilityType::from(code);
631            assert_eq!(ty, BgpCapabilityType::Unknown(code));
632            assert!(!ty.is_deprecated() && !ty.is_reserved());
633        }
634
635        // valid capabilities
636        assert_eq!(
637            BgpCapabilityType::from(1),
638            BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4
639        );
640        assert_eq!(
641            BgpCapabilityType::from(2),
642            BgpCapabilityType::ROUTE_REFRESH_CAPABILITY_FOR_BGP_4
643        );
644        assert_eq!(
645            BgpCapabilityType::from(3),
646            BgpCapabilityType::OUTBOUND_ROUTE_FILTERING_CAPABILITY
647        );
648        assert_eq!(
649            BgpCapabilityType::from(5),
650            BgpCapabilityType::EXTENDED_NEXT_HOP_ENCODING
651        );
652        assert_eq!(
653            BgpCapabilityType::from(6),
654            BgpCapabilityType::BGP_EXTENDED_MESSAGE
655        );
656        assert_eq!(
657            BgpCapabilityType::from(7),
658            BgpCapabilityType::BGPSEC_CAPABILITY
659        );
660        assert_eq!(
661            BgpCapabilityType::from(8),
662            BgpCapabilityType::MULTIPLE_LABELS_CAPABILITY
663        );
664        assert_eq!(BgpCapabilityType::from(9), BgpCapabilityType::BGP_ROLE);
665
666        assert_eq!(
667            BgpCapabilityType::from(64),
668            BgpCapabilityType::GRACEFUL_RESTART_CAPABILITY
669        );
670        assert_eq!(
671            BgpCapabilityType::from(65),
672            BgpCapabilityType::SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY
673        );
674        assert_eq!(
675            BgpCapabilityType::from(67),
676            BgpCapabilityType::SUPPORT_FOR_DYNAMIC_CAPABILITY
677        );
678        assert_eq!(
679            BgpCapabilityType::from(68),
680            BgpCapabilityType::MULTISESSION_BGP_CAPABILITY
681        );
682        assert_eq!(
683            BgpCapabilityType::from(69),
684            BgpCapabilityType::ADD_PATH_CAPABILITY
685        );
686        assert_eq!(
687            BgpCapabilityType::from(70),
688            BgpCapabilityType::ENHANCED_ROUTE_REFRESH_CAPABILITY
689        );
690        assert_eq!(
691            BgpCapabilityType::from(71),
692            BgpCapabilityType::LONG_LIVED_GRACEFUL_RESTART_CAPABILITY
693        );
694        assert_eq!(
695            BgpCapabilityType::from(72),
696            BgpCapabilityType::ROUTING_POLICY_DISTRIBUTION
697        );
698        assert_eq!(
699            BgpCapabilityType::from(73),
700            BgpCapabilityType::FQDN_CAPABILITY
701        );
702    }
703
704    #[test]
705    fn test_reserved_for_experimental() {
706        let experimental_ranges = [239..=254];
707        for code in <[_; 1]>::into_iter(experimental_ranges).flatten() {
708            let ty = BgpCapabilityType::from(code);
709            assert_eq!(ty, BgpCapabilityType::Unknown(code));
710            assert!(ty.is_reserved_for_experimental_use());
711        }
712    }
713
714    #[test]
715    #[cfg(feature = "serde")]
716    fn test_serde() {
717        let ty = BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4;
718        let serialized = serde_json::to_string(&ty).unwrap();
719        let deserialized: BgpCapabilityType = serde_json::from_str(&serialized).unwrap();
720        assert_eq!(ty, deserialized);
721    }
722
723    #[test]
724    fn test_extended_next_hop_capability() {
725        use crate::models::network::{Afi, Safi};
726
727        // Create capability with RFC 8950 standard combinations
728        let entries = vec![
729            ExtendedNextHopEntry {
730                nlri_afi: Afi::Ipv4,
731                nlri_safi: Safi::Unicast,
732                nexthop_afi: Afi::Ipv6,
733            },
734            ExtendedNextHopEntry {
735                nlri_afi: Afi::Ipv4,
736                nlri_safi: Safi::MplsVpn,
737                nexthop_afi: Afi::Ipv6,
738            },
739        ];
740
741        let capability = ExtendedNextHopCapability::new(entries);
742
743        // Test supports() method
744        assert!(capability.supports(Afi::Ipv4, Safi::Unicast, Afi::Ipv6));
745        assert!(capability.supports(Afi::Ipv4, Safi::MplsVpn, Afi::Ipv6));
746        assert!(!capability.supports(Afi::Ipv4, Safi::Multicast, Afi::Ipv6));
747        assert!(!capability.supports(Afi::Ipv6, Safi::Unicast, Afi::Ipv6));
748
749        // Test supported_nlri_for_nexthop() method
750        let supported = capability.supported_nlri_for_nexthop(Afi::Ipv6);
751        assert_eq!(supported.len(), 2);
752        assert!(supported.contains(&(Afi::Ipv4, Safi::Unicast)));
753        assert!(supported.contains(&(Afi::Ipv4, Safi::MplsVpn)));
754
755        let no_support = capability.supported_nlri_for_nexthop(Afi::Ipv4);
756        assert!(no_support.is_empty());
757    }
758
759    #[test]
760    fn test_extended_next_hop_capability_parsing() {
761        use crate::models::network::{Afi, Safi};
762
763        // Test parsing valid capability data
764        // Entry 1: IPv4 Unicast (AFI=1, SAFI=1) with IPv6 NextHop (AFI=2)
765        // Entry 2: IPv4 MPLS VPN (AFI=1, SAFI=128) with IPv6 NextHop (AFI=2)
766        let capability_bytes = Bytes::from(vec![
767            0x00, 0x01, // NLRI AFI = 1 (IPv4)
768            0x00, 0x01, // NLRI SAFI = 1 (Unicast)
769            0x00, 0x02, // NextHop AFI = 2 (IPv6)
770            0x00, 0x01, // NLRI AFI = 1 (IPv4)
771            0x00, 0x80, // NLRI SAFI = 128 (MPLS VPN)
772            0x00, 0x02, // NextHop AFI = 2 (IPv6)
773        ]);
774
775        let parsed = ExtendedNextHopCapability::parse(capability_bytes).unwrap();
776
777        assert_eq!(parsed.entries.len(), 2);
778
779        // Check first entry
780        assert_eq!(parsed.entries[0].nlri_afi, Afi::Ipv4);
781        assert_eq!(parsed.entries[0].nlri_safi, Safi::Unicast);
782        assert_eq!(parsed.entries[0].nexthop_afi, Afi::Ipv6);
783
784        // Check second entry
785        assert_eq!(parsed.entries[1].nlri_afi, Afi::Ipv4);
786        assert_eq!(parsed.entries[1].nlri_safi, Safi::MplsVpn);
787        assert_eq!(parsed.entries[1].nexthop_afi, Afi::Ipv6);
788
789        // Test functionality
790        assert!(parsed.supports(Afi::Ipv4, Safi::Unicast, Afi::Ipv6));
791        assert!(parsed.supports(Afi::Ipv4, Safi::MplsVpn, Afi::Ipv6));
792        assert!(!parsed.supports(Afi::Ipv4, Safi::Multicast, Afi::Ipv6));
793    }
794
795    #[test]
796    fn test_extended_next_hop_capability_encoding() {
797        use crate::models::network::{Afi, Safi};
798
799        let entries = vec![
800            ExtendedNextHopEntry {
801                nlri_afi: Afi::Ipv4,
802                nlri_safi: Safi::Unicast,
803                nexthop_afi: Afi::Ipv6,
804            },
805            ExtendedNextHopEntry {
806                nlri_afi: Afi::Ipv4,
807                nlri_safi: Safi::MplsVpn,
808                nexthop_afi: Afi::Ipv6,
809            },
810        ];
811
812        let capability = ExtendedNextHopCapability::new(entries);
813        let encoded = capability.encode();
814
815        let expected = vec![
816            0x00, 0x01, // NLRI AFI = 1 (IPv4)
817            0x00, 0x01, // NLRI SAFI = 1 (Unicast)
818            0x00, 0x02, // NextHop AFI = 2 (IPv6)
819            0x00, 0x01, // NLRI AFI = 1 (IPv4)
820            0x00, 0x80, // NLRI SAFI = 128 (MPLS VPN)
821            0x00, 0x02, // NextHop AFI = 2 (IPv6)
822        ];
823
824        assert_eq!(encoded.to_vec(), expected);
825    }
826
827    #[test]
828    fn test_extended_next_hop_capability_round_trip() {
829        use crate::models::network::{Afi, Safi};
830
831        let original_entries = vec![
832            ExtendedNextHopEntry {
833                nlri_afi: Afi::Ipv4,
834                nlri_safi: Safi::Unicast,
835                nexthop_afi: Afi::Ipv6,
836            },
837            ExtendedNextHopEntry {
838                nlri_afi: Afi::Ipv4,
839                nlri_safi: Safi::MulticastVpn,
840                nexthop_afi: Afi::Ipv6,
841            },
842        ];
843
844        let original = ExtendedNextHopCapability::new(original_entries);
845        let encoded = original.encode();
846        let parsed = ExtendedNextHopCapability::parse(encoded).unwrap();
847
848        assert_eq!(original, parsed);
849    }
850
851    #[test]
852    fn test_extended_next_hop_capability_invalid_length() {
853        // Test with invalid length (not divisible by 6)
854        let invalid_bytes = Bytes::from(vec![0x00, 0x01, 0x00, 0x01, 0x00]); // 5 bytes
855        let result = ExtendedNextHopCapability::parse(invalid_bytes);
856        assert!(result.is_err());
857
858        if let Err(ParserError::ParseError(msg)) = result {
859            assert!(msg.contains("not divisible by 6"));
860        } else {
861            panic!("Expected ParseError with divisibility message");
862        }
863    }
864
865    #[test]
866    fn test_extended_next_hop_capability_empty() {
867        // Test with empty capability (valid - no entries)
868        let empty_bytes = Bytes::from(vec![]);
869        let parsed = ExtendedNextHopCapability::parse(empty_bytes).unwrap();
870        assert_eq!(parsed.entries.len(), 0);
871
872        // Test encoding empty capability
873        let empty_capability = ExtendedNextHopCapability::new(vec![]);
874        let encoded = empty_capability.encode();
875        assert_eq!(encoded.len(), 0);
876    }
877
878    #[test]
879    fn test_multiprotocol_extensions_capability() {
880        use crate::models::network::{Afi, Safi};
881
882        // Test IPv4 Unicast capability
883        let capability = MultiprotocolExtensionsCapability::new(Afi::Ipv4, Safi::Unicast);
884
885        // Test encoding
886        let encoded = capability.encode();
887        assert_eq!(encoded.len(), 4);
888        assert_eq!(encoded[0], 0x00); // AFI high byte
889        assert_eq!(encoded[1], 0x01); // AFI low byte (IPv4)
890        assert_eq!(encoded[2], 0x00); // Reserved
891        assert_eq!(encoded[3], 0x01); // SAFI (Unicast)
892
893        // Test parsing
894        let parsed = MultiprotocolExtensionsCapability::parse(encoded).unwrap();
895        assert_eq!(parsed.afi, Afi::Ipv4);
896        assert_eq!(parsed.safi, Safi::Unicast);
897        assert_eq!(parsed, capability);
898    }
899
900    #[test]
901    fn test_multiprotocol_extensions_capability_ipv6() {
902        use crate::models::network::{Afi, Safi};
903
904        // Test IPv6 Multicast capability
905        let capability = MultiprotocolExtensionsCapability::new(Afi::Ipv6, Safi::Multicast);
906
907        let encoded = capability.encode();
908        let parsed = MultiprotocolExtensionsCapability::parse(encoded).unwrap();
909        assert_eq!(parsed.afi, Afi::Ipv6);
910        assert_eq!(parsed.safi, Safi::Multicast);
911    }
912
913    #[test]
914    fn test_multiprotocol_extensions_capability_invalid_length() {
915        // Test with invalid length
916        let invalid_bytes = Bytes::from(vec![0x00, 0x01, 0x00]); // 3 bytes instead of 4
917        let result = MultiprotocolExtensionsCapability::parse(invalid_bytes);
918        assert!(result.is_err());
919    }
920
921    #[test]
922    fn test_graceful_restart_capability() {
923        use crate::models::network::{Afi, Safi};
924
925        // Create capability with restart state and multiple address families
926        let address_families = vec![
927            GracefulRestartAddressFamily {
928                afi: Afi::Ipv4,
929                safi: Safi::Unicast,
930                forwarding_state: true,
931            },
932            GracefulRestartAddressFamily {
933                afi: Afi::Ipv6,
934                safi: Safi::Unicast,
935                forwarding_state: false,
936            },
937        ];
938
939        let capability = GracefulRestartCapability::new(true, 180, address_families);
940
941        // Test encoding
942        let encoded = capability.encode();
943        assert_eq!(encoded.len(), 2 + 2 * 4); // 2 header bytes + 2 AF entries * 4 bytes each
944
945        // Test parsing
946        let parsed = GracefulRestartCapability::parse(encoded).unwrap();
947        assert!(parsed.restart_state);
948        assert_eq!(parsed.restart_time, 180);
949        assert_eq!(parsed.address_families.len(), 2);
950
951        // Check first AF
952        assert_eq!(parsed.address_families[0].afi, Afi::Ipv4);
953        assert_eq!(parsed.address_families[0].safi, Safi::Unicast);
954        assert!(parsed.address_families[0].forwarding_state);
955
956        // Check second AF
957        assert_eq!(parsed.address_families[1].afi, Afi::Ipv6);
958        assert_eq!(parsed.address_families[1].safi, Safi::Unicast);
959        assert!(!parsed.address_families[1].forwarding_state);
960    }
961
962    #[test]
963    fn test_graceful_restart_capability_no_restart_state() {
964        // Test without restart state flag
965        let capability = GracefulRestartCapability::new(false, 300, vec![]);
966
967        let encoded = capability.encode();
968        let parsed = GracefulRestartCapability::parse(encoded).unwrap();
969        assert!(!parsed.restart_state);
970        assert_eq!(parsed.restart_time, 300);
971        assert_eq!(parsed.address_families.len(), 0);
972    }
973
974    #[test]
975    fn test_graceful_restart_capability_invalid_length() {
976        // Test with length that's not divisible by 4 after header
977        let invalid_bytes = Bytes::from(vec![0x80, 0xB4, 0x00, 0x01, 0x01]); // 5 bytes total, 3 after header
978        let result = GracefulRestartCapability::parse(invalid_bytes);
979        assert!(result.is_err());
980    }
981
982    #[test]
983    fn test_add_path_capability() {
984        use crate::models::network::{Afi, Safi};
985
986        // Create capability with multiple address families
987        let address_families = vec![
988            AddPathAddressFamily {
989                afi: Afi::Ipv4,
990                safi: Safi::Unicast,
991                send_receive: AddPathSendReceive::SendReceive,
992            },
993            AddPathAddressFamily {
994                afi: Afi::Ipv6,
995                safi: Safi::Unicast,
996                send_receive: AddPathSendReceive::Receive,
997            },
998        ];
999
1000        let capability = AddPathCapability::new(address_families);
1001
1002        // Test encoding
1003        let encoded = capability.encode();
1004        assert_eq!(encoded.len(), 2 * 4); // 2 AF entries * 4 bytes each
1005
1006        // Test parsing
1007        let parsed = AddPathCapability::parse(encoded).unwrap();
1008        assert_eq!(parsed.address_families.len(), 2);
1009
1010        // Check first AF
1011        assert_eq!(parsed.address_families[0].afi, Afi::Ipv4);
1012        assert_eq!(parsed.address_families[0].safi, Safi::Unicast);
1013        assert_eq!(
1014            parsed.address_families[0].send_receive,
1015            AddPathSendReceive::SendReceive
1016        );
1017
1018        // Check second AF
1019        assert_eq!(parsed.address_families[1].afi, Afi::Ipv6);
1020        assert_eq!(parsed.address_families[1].safi, Safi::Unicast);
1021        assert_eq!(
1022            parsed.address_families[1].send_receive,
1023            AddPathSendReceive::Receive
1024        );
1025    }
1026
1027    #[test]
1028    fn test_add_path_send_receive_values() {
1029        use AddPathSendReceive::*;
1030
1031        assert_eq!(Receive as u8, 1);
1032        assert_eq!(Send as u8, 2);
1033        assert_eq!(SendReceive as u8, 3);
1034
1035        assert_eq!(AddPathSendReceive::try_from(1).unwrap(), Receive);
1036        assert_eq!(AddPathSendReceive::try_from(2).unwrap(), Send);
1037        assert_eq!(AddPathSendReceive::try_from(3).unwrap(), SendReceive);
1038
1039        // Invalid value
1040        assert!(AddPathSendReceive::try_from(4).is_err());
1041    }
1042
1043    #[test]
1044    fn test_add_path_capability_invalid_length() {
1045        // Test with length that's not divisible by 4
1046        let invalid_bytes = Bytes::from(vec![0x00, 0x01, 0x01]); // 3 bytes
1047        let result = AddPathCapability::parse(invalid_bytes);
1048        assert!(result.is_err());
1049    }
1050
1051    #[test]
1052    fn test_add_path_capability_empty() {
1053        // Test with empty capability (valid - no entries)
1054        let empty_bytes = Bytes::from(vec![]);
1055        let parsed = AddPathCapability::parse(empty_bytes).unwrap();
1056        assert_eq!(parsed.address_families.len(), 0);
1057
1058        // Test encoding empty capability
1059        let empty_capability = AddPathCapability::new(vec![]);
1060        let encoded = empty_capability.encode();
1061        assert_eq!(encoded.len(), 0);
1062    }
1063
1064    #[test]
1065    fn test_route_refresh_capability() {
1066        // Test creation
1067        let capability = RouteRefreshCapability::new();
1068
1069        // Test encoding (should be empty)
1070        let encoded = capability.encode();
1071        assert_eq!(encoded.len(), 0);
1072
1073        // Test parsing (should accept empty data)
1074        let parsed = RouteRefreshCapability::parse(encoded).unwrap();
1075        assert_eq!(parsed, capability);
1076    }
1077
1078    #[test]
1079    fn test_route_refresh_capability_invalid_length() {
1080        // Test with non-empty data (should fail)
1081        let invalid_bytes = Bytes::from(vec![0x01]);
1082        let result = RouteRefreshCapability::parse(invalid_bytes);
1083        assert!(result.is_err());
1084    }
1085
1086    #[test]
1087    fn test_four_octet_as_capability() {
1088        // Test various AS numbers
1089        let test_cases = [0, 65535, 65536, 4294967295];
1090
1091        for asn in test_cases {
1092            let capability = FourOctetAsCapability::new(asn);
1093
1094            // Test encoding
1095            let encoded = capability.encode();
1096            assert_eq!(encoded.len(), 4);
1097
1098            // Test parsing
1099            let parsed = FourOctetAsCapability::parse(encoded).unwrap();
1100            assert_eq!(parsed.asn, asn);
1101            assert_eq!(parsed, capability);
1102        }
1103    }
1104
1105    #[test]
1106    fn test_four_octet_as_capability_invalid_length() {
1107        // Test with wrong length
1108        let invalid_bytes = Bytes::from(vec![0x00, 0x01, 0x00]); // 3 bytes instead of 4
1109        let result = FourOctetAsCapability::parse(invalid_bytes);
1110        assert!(result.is_err());
1111    }
1112
1113    #[test]
1114    fn test_bgp_role_capability() {
1115        use BgpRole::*;
1116
1117        // Test all valid role values
1118        let test_cases = [
1119            (Provider, 0),
1120            (RouteServer, 1),
1121            (RouteServerClient, 2),
1122            (Customer, 3),
1123            (Peer, 4),
1124        ];
1125
1126        for (role, expected_value) in test_cases {
1127            let capability = BgpRoleCapability::new(role);
1128
1129            // Test encoding
1130            let encoded = capability.encode();
1131            assert_eq!(encoded.len(), 1);
1132            assert_eq!(encoded[0], expected_value);
1133
1134            // Test parsing
1135            let parsed = BgpRoleCapability::parse(encoded).unwrap();
1136            assert_eq!(parsed.role, role);
1137            assert_eq!(parsed, capability);
1138        }
1139    }
1140
1141    #[test]
1142    fn test_bgp_role_values() {
1143        use BgpRole::*;
1144
1145        // Test enum values
1146        assert_eq!(Provider as u8, 0);
1147        assert_eq!(RouteServer as u8, 1);
1148        assert_eq!(RouteServerClient as u8, 2);
1149        assert_eq!(Customer as u8, 3);
1150        assert_eq!(Peer as u8, 4);
1151
1152        // Test TryFrom conversion
1153        assert_eq!(BgpRole::try_from(0).unwrap(), Provider);
1154        assert_eq!(BgpRole::try_from(1).unwrap(), RouteServer);
1155        assert_eq!(BgpRole::try_from(2).unwrap(), RouteServerClient);
1156        assert_eq!(BgpRole::try_from(3).unwrap(), Customer);
1157        assert_eq!(BgpRole::try_from(4).unwrap(), Peer);
1158
1159        // Test invalid value
1160        assert!(BgpRole::try_from(5).is_err());
1161        assert!(BgpRole::try_from(255).is_err());
1162    }
1163
1164    #[test]
1165    fn test_bgp_role_capability_invalid_length() {
1166        // Test with wrong length
1167        let invalid_bytes = Bytes::from(vec![0x00, 0x01]); // 2 bytes instead of 1
1168        let result = BgpRoleCapability::parse(invalid_bytes);
1169        assert!(result.is_err());
1170
1171        // Test with empty data
1172        let empty_bytes = Bytes::from(vec![]);
1173        let result = BgpRoleCapability::parse(empty_bytes);
1174        assert!(result.is_err());
1175    }
1176
1177    #[test]
1178    fn test_bgp_role_capability_invalid_value() {
1179        // Test with invalid role value
1180        let invalid_bytes = Bytes::from(vec![5]); // 5 is not a valid role
1181        let result = BgpRoleCapability::parse(invalid_bytes);
1182        assert!(result.is_err());
1183    }
1184
1185    #[test]
1186    fn test_bgp_extended_message_capability() {
1187        // Test creation
1188        let capability = BgpExtendedMessageCapability::new();
1189
1190        // Test encoding (should be empty)
1191        let encoded = capability.encode();
1192        assert_eq!(encoded.len(), 0);
1193
1194        // Test parsing (should accept empty data)
1195        let parsed = BgpExtendedMessageCapability::parse(encoded).unwrap();
1196        assert_eq!(parsed, capability);
1197    }
1198
1199    #[test]
1200    fn test_bgp_extended_message_capability_invalid_length() {
1201        // Test with non-empty data (should fail)
1202        let invalid_bytes = Bytes::from(vec![0x01]);
1203        let result = BgpExtendedMessageCapability::parse(invalid_bytes);
1204        assert!(result.is_err());
1205    }
1206}