bgpkit_parser/models/bgp/flowspec/
mod.rs

1use crate::models::*;
2
3pub mod nlri;
4pub mod operators;
5
6#[cfg(test)]
7mod tests;
8
9pub use nlri::*;
10pub use operators::*;
11
12/// Flow Specification NLRI containing an ordered list of components
13#[derive(Debug, Clone, PartialEq, Eq)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct FlowSpecNlri {
16    pub components: Vec<FlowSpecComponent>,
17}
18
19/// Individual Flow-Spec component types as defined in RFC 8955/8956
20#[derive(Debug, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub enum FlowSpecComponent {
23    /// Type 1: Destination Prefix
24    DestinationPrefix(NetworkPrefix),
25    /// Type 2: Source Prefix  
26    SourcePrefix(NetworkPrefix),
27    /// Type 3: IP Protocol
28    IpProtocol(Vec<NumericOperator>),
29    /// Type 4: Port (source OR destination)
30    Port(Vec<NumericOperator>),
31    /// Type 5: Destination Port
32    DestinationPort(Vec<NumericOperator>),
33    /// Type 6: Source Port
34    SourcePort(Vec<NumericOperator>),
35    /// Type 7: ICMP Type (IPv4) / ICMPv6 Type (IPv6)
36    IcmpType(Vec<NumericOperator>),
37    /// Type 8: ICMP Code (IPv4) / ICMPv6 Code (IPv6)
38    IcmpCode(Vec<NumericOperator>),
39    /// Type 9: TCP Flags
40    TcpFlags(Vec<BitmaskOperator>),
41    /// Type 10: Packet Length
42    PacketLength(Vec<NumericOperator>),
43    /// Type 11: DSCP
44    Dscp(Vec<NumericOperator>),
45    /// Type 12: Fragment
46    Fragment(Vec<BitmaskOperator>),
47    /// Type 13: Flow Label (IPv6 only)
48    FlowLabel(Vec<NumericOperator>),
49    /// IPv6 Destination Prefix with offset
50    DestinationIpv6Prefix { offset: u8, prefix: NetworkPrefix },
51    /// IPv6 Source Prefix with offset
52    SourceIpv6Prefix { offset: u8, prefix: NetworkPrefix },
53}
54
55impl FlowSpecComponent {
56    /// Get the numeric type identifier for this component
57    pub const fn component_type(&self) -> u8 {
58        match self {
59            FlowSpecComponent::DestinationPrefix(_)
60            | FlowSpecComponent::DestinationIpv6Prefix { .. } => 1,
61            FlowSpecComponent::SourcePrefix(_) | FlowSpecComponent::SourceIpv6Prefix { .. } => 2,
62            FlowSpecComponent::IpProtocol(_) => 3,
63            FlowSpecComponent::Port(_) => 4,
64            FlowSpecComponent::DestinationPort(_) => 5,
65            FlowSpecComponent::SourcePort(_) => 6,
66            FlowSpecComponent::IcmpType(_) => 7,
67            FlowSpecComponent::IcmpCode(_) => 8,
68            FlowSpecComponent::TcpFlags(_) => 9,
69            FlowSpecComponent::PacketLength(_) => 10,
70            FlowSpecComponent::Dscp(_) => 11,
71            FlowSpecComponent::Fragment(_) => 12,
72            FlowSpecComponent::FlowLabel(_) => 13,
73        }
74    }
75
76    /// Returns true if this component uses numeric operators
77    pub const fn uses_numeric_operators(&self) -> bool {
78        matches!(
79            self,
80            FlowSpecComponent::IpProtocol(_)
81                | FlowSpecComponent::Port(_)
82                | FlowSpecComponent::DestinationPort(_)
83                | FlowSpecComponent::SourcePort(_)
84                | FlowSpecComponent::IcmpType(_)
85                | FlowSpecComponent::IcmpCode(_)
86                | FlowSpecComponent::PacketLength(_)
87                | FlowSpecComponent::Dscp(_)
88                | FlowSpecComponent::FlowLabel(_)
89        )
90    }
91
92    /// Returns true if this component uses bitmask operators
93    pub const fn uses_bitmask_operators(&self) -> bool {
94        matches!(
95            self,
96            FlowSpecComponent::TcpFlags(_) | FlowSpecComponent::Fragment(_)
97        )
98    }
99}
100
101impl FlowSpecNlri {
102    /// Create a new Flow-Spec NLRI with the given components
103    pub fn new(components: Vec<FlowSpecComponent>) -> Self {
104        FlowSpecNlri { components }
105    }
106
107    /// Get all components of this NLRI
108    pub fn components(&self) -> &[FlowSpecComponent] {
109        &self.components
110    }
111
112    /// Check if this Flow-Spec rule matches IPv4 traffic
113    pub fn is_ipv4(&self) -> bool {
114        self.components.iter().any(|c| {
115            matches!(c,
116                FlowSpecComponent::DestinationPrefix(prefix) |
117                FlowSpecComponent::SourcePrefix(prefix)
118                if matches!(prefix.prefix, ipnet::IpNet::V4(_))
119            )
120        })
121    }
122
123    /// Check if this Flow-Spec rule matches IPv6 traffic
124    pub fn is_ipv6(&self) -> bool {
125        self.components.iter().any(|c| {
126            matches!(c,
127                FlowSpecComponent::DestinationPrefix(prefix) |
128                FlowSpecComponent::SourcePrefix(prefix)
129                if matches!(prefix.prefix, ipnet::IpNet::V6(_))
130            )
131        }) || self.components.iter().any(|c| {
132            matches!(
133                c,
134                FlowSpecComponent::DestinationIpv6Prefix { .. }
135                    | FlowSpecComponent::SourceIpv6Prefix { .. }
136                    | FlowSpecComponent::FlowLabel(_)
137            )
138        })
139    }
140}
141
142/// Flow-Spec parsing and validation errors
143#[derive(Debug, Clone, PartialEq, Eq)]
144#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
145pub enum FlowSpecError {
146    /// Components not in ascending type order
147    InvalidComponentOrder {
148        expected_greater_than: u8,
149        found: u8,
150    },
151    /// Invalid operator encoding
152    InvalidOperator(u8),
153    /// Invalid component type
154    InvalidComponentType(u8),
155    /// Insufficient data for parsing
156    InsufficientData,
157    /// Invalid prefix encoding
158    InvalidPrefix,
159    /// Invalid value length
160    InvalidValueLength(u8),
161}
162
163impl std::fmt::Display for FlowSpecError {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        match self {
166            FlowSpecError::InvalidComponentOrder {
167                expected_greater_than,
168                found,
169            } => {
170                write!(
171                    f,
172                    "Invalid component order: expected type > {}, but found {}",
173                    expected_greater_than, found
174                )
175            }
176            FlowSpecError::InvalidOperator(op) => {
177                write!(f, "Invalid operator: 0x{:02X}", op)
178            }
179            FlowSpecError::InvalidComponentType(t) => {
180                write!(f, "Invalid component type: {}", t)
181            }
182            FlowSpecError::InsufficientData => {
183                write!(f, "Insufficient data for parsing")
184            }
185            FlowSpecError::InvalidPrefix => {
186                write!(f, "Invalid prefix encoding")
187            }
188            FlowSpecError::InvalidValueLength(len) => {
189                write!(f, "Invalid value length: {}", len)
190            }
191        }
192    }
193}
194
195impl std::error::Error for FlowSpecError {}