Skip to main content

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