1use crate::models::{Afi, AttrType, Bgp4MpType, BgpState, EntryType, Safi, TableDumpV2Type};
5use num_enum::TryFromPrimitiveError;
6#[cfg(feature = "oneio")]
7use oneio::OneIoError;
8use std::fmt::{Display, Formatter};
9use std::io::ErrorKind;
10use std::{error::Error, fmt, io};
11
12#[derive(Debug)]
13pub enum ParserError {
14 IoError(io::Error),
15 EofError(io::Error),
16 #[cfg(feature = "oneio")]
17 OneIoError(OneIoError),
18 EofExpected,
19 ParseError(String),
20 TruncatedMsg(String),
21 Unsupported(String),
22 FilterError(String),
23 InvalidLabeledNlriLength,
26 TruncatedLabeledNlri,
28 TruncatedPrefix,
30 MaxLabelStackDepthExceeded,
32 PeerMaxLabelsExceeded,
35 InvalidPrefix,
37}
38
39impl Error for ParserError {}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
48#[non_exhaustive]
49pub enum EncodingError {
50 ValueTooLarge {
56 field: &'static str,
57 actual: usize,
58 max: usize,
59 },
60 Unencodable { field: &'static str, reason: String },
64}
65
66impl EncodingError {
67 pub(crate) fn too_large(field: &'static str, actual: usize, max: usize) -> Self {
68 EncodingError::ValueTooLarge { field, actual, max }
69 }
70
71 pub(crate) fn unencodable(field: &'static str, reason: impl Into<String>) -> Self {
72 EncodingError::Unencodable {
73 field,
74 reason: reason.into(),
75 }
76 }
77}
78
79pub(crate) fn check_max(
85 field: &'static str,
86 actual: usize,
87 max: usize,
88) -> Result<usize, EncodingError> {
89 if actual > max {
90 return Err(EncodingError::too_large(field, actual, max));
91 }
92 Ok(actual)
93}
94
95impl Display for EncodingError {
96 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
97 match self {
98 EncodingError::ValueTooLarge { field, actual, max } => write!(
99 f,
100 "encoding error: {field} ({actual}) exceeds maximum ({max})"
101 ),
102 EncodingError::Unencodable { field, reason } => {
103 write!(f, "encoding error: {field} cannot be encoded: {reason}")
104 }
105 }
106 }
107}
108
109impl Error for EncodingError {}
110
111#[derive(Debug)]
112pub struct ParserErrorWithBytes {
113 pub error: ParserError,
114 pub bytes: Option<Vec<u8>>,
115}
116
117impl Display for ParserErrorWithBytes {
118 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
119 write!(f, "{}", self.error)
120 }
121}
122
123impl Error for ParserErrorWithBytes {}
124
125impl Display for ParserError {
128 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129 match self {
130 ParserError::IoError(e) => write!(f, "Error: {e}"),
131 ParserError::EofError(e) => write!(f, "Error: {e}"),
132 ParserError::ParseError(s) => write!(f, "Error: {s}"),
133 ParserError::TruncatedMsg(s) => write!(f, "Error: {s}"),
134 ParserError::Unsupported(s) => write!(f, "Error: {s}"),
135 ParserError::EofExpected => write!(f, "Error: reach end of file"),
136 #[cfg(feature = "oneio")]
137 ParserError::OneIoError(e) => write!(f, "Error: {e}"),
138 ParserError::FilterError(e) => write!(f, "Error: {e}"),
139 ParserError::InvalidLabeledNlriLength => {
140 write!(f, "Error: invalid labeled NLRI length field")
141 }
142 ParserError::TruncatedLabeledNlri => write!(f, "Error: truncated labeled NLRI"),
143 ParserError::TruncatedPrefix => write!(f, "Error: truncated prefix in NLRI"),
144 ParserError::MaxLabelStackDepthExceeded => write!(
145 f,
146 "Error: max label stack depth exceeded without finding BoS bit"
147 ),
148 ParserError::PeerMaxLabelsExceeded => write!(
149 f,
150 "Error: received more labels than peer advertised maximum"
151 ),
152 ParserError::InvalidPrefix => write!(f, "Error: invalid prefix in NLRI"),
153 }
154 }
155}
156
157#[cfg(feature = "oneio")]
158impl From<OneIoError> for ParserErrorWithBytes {
159 fn from(error: OneIoError) -> Self {
160 ParserErrorWithBytes {
161 error: ParserError::OneIoError(error),
162 bytes: None,
163 }
164 }
165}
166
167#[cfg(feature = "oneio")]
168impl From<OneIoError> for ParserError {
169 fn from(error: OneIoError) -> Self {
170 ParserError::OneIoError(error)
171 }
172}
173
174impl From<ParserError> for ParserErrorWithBytes {
175 fn from(error: ParserError) -> Self {
176 ParserErrorWithBytes { error, bytes: None }
177 }
178}
179
180impl From<io::Error> for ParserError {
181 fn from(io_error: io::Error) -> Self {
182 match io_error.kind() {
183 ErrorKind::UnexpectedEof => ParserError::EofError(io_error),
184 _ => ParserError::IoError(io_error),
185 }
186 }
187}
188
189impl From<TryFromPrimitiveError<Bgp4MpType>> for ParserError {
190 fn from(value: TryFromPrimitiveError<Bgp4MpType>) -> Self {
191 ParserError::ParseError(format!("cannot parse bgp4mp subtype: {}", value.number))
192 }
193}
194
195impl From<TryFromPrimitiveError<BgpState>> for ParserError {
196 fn from(value: TryFromPrimitiveError<BgpState>) -> Self {
197 ParserError::ParseError(format!("cannot parse bgp4mp state: {}", value.number))
198 }
199}
200
201impl From<TryFromPrimitiveError<TableDumpV2Type>> for ParserError {
202 fn from(value: TryFromPrimitiveError<TableDumpV2Type>) -> Self {
203 ParserError::ParseError(format!("cannot parse table dump v2 type: {}", value.number))
204 }
205}
206
207impl From<TryFromPrimitiveError<EntryType>> for ParserError {
208 fn from(value: TryFromPrimitiveError<EntryType>) -> Self {
209 ParserError::ParseError(format!("cannot parse entry type: {}", value.number))
210 }
211}
212
213impl From<TryFromPrimitiveError<Afi>> for ParserError {
214 fn from(value: TryFromPrimitiveError<Afi>) -> Self {
215 ParserError::ParseError(format!("Unknown AFI type: {}", value.number))
216 }
217}
218
219impl From<TryFromPrimitiveError<Safi>> for ParserError {
220 fn from(value: TryFromPrimitiveError<Safi>) -> Self {
221 ParserError::ParseError(format!("Unknown SAFI type: {}", value.number))
222 }
223}
224
225#[derive(Debug, Clone, PartialEq, Eq)]
231#[non_exhaustive]
232pub enum BgpValidationWarning {
233 AttributeFlagsError {
235 attr_type: AttrType,
236 expected_flags: u8,
237 actual_flags: u8,
238 },
239 AttributeLengthError {
241 attr_type: AttrType,
242 expected_length: Option<usize>,
243 actual_length: usize,
244 },
245 MissingWellKnownAttribute { attr_type: AttrType },
247 UnrecognizedWellKnownAttribute { attr_type_code: u8 },
249 InvalidOriginAttribute { value: u8 },
251 InvalidNextHopAttribute { reason: String },
253 MalformedAsPath { reason: String },
255 OptionalAttributeError { attr_type: AttrType, reason: String },
257 DuplicateAttribute { attr_type: AttrType },
259 InvalidNetworkField { reason: String },
261 MalformedAttributeList { reason: String },
263 PartialAttributeError { attr_type: AttrType, reason: String },
265 MalformedNlri {
275 nlri_type: &'static str,
277 reason: String,
279 raw_bytes: Vec<u8>,
281 },
282 UnknownRouteRefreshSubtype { subtype: u8 },
286 InvalidRouteRefreshLength {
292 subtype: u8,
293 length: usize,
295 },
296}
297
298impl Display for BgpValidationWarning {
299 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
300 match self {
301 BgpValidationWarning::AttributeFlagsError { attr_type, expected_flags, actual_flags } => {
302 write!(f, "Attribute flags error for {attr_type:?}: expected 0x{expected_flags:02x}, got 0x{actual_flags:02x}")
303 }
304 BgpValidationWarning::AttributeLengthError { attr_type, expected_length, actual_length } => {
305 match expected_length {
306 Some(expected) => write!(f, "Attribute length error for {attr_type:?}: expected {expected}, got {actual_length}"),
307 None => write!(f, "Attribute length error for {attr_type:?}: invalid length {actual_length}"),
308 }
309 }
310 BgpValidationWarning::MissingWellKnownAttribute { attr_type } => {
311 write!(f, "Missing well-known mandatory attribute: {attr_type:?}")
312 }
313 BgpValidationWarning::UnrecognizedWellKnownAttribute { attr_type_code } => {
314 write!(f, "Unrecognized well-known attribute: type code {attr_type_code}")
315 }
316 BgpValidationWarning::InvalidOriginAttribute { value } => {
317 write!(f, "Invalid origin attribute value: {value}")
318 }
319 BgpValidationWarning::InvalidNextHopAttribute { reason } => {
320 write!(f, "Invalid next hop attribute: {reason}")
321 }
322 BgpValidationWarning::MalformedAsPath { reason } => {
323 write!(f, "Malformed AS_PATH: {reason}")
324 }
325 BgpValidationWarning::OptionalAttributeError { attr_type, reason } => {
326 write!(f, "Optional attribute error for {attr_type:?}: {reason}")
327 }
328 BgpValidationWarning::DuplicateAttribute { attr_type } => {
329 write!(f, "Duplicate attribute: {attr_type:?}")
330 }
331 BgpValidationWarning::InvalidNetworkField { reason } => {
332 write!(f, "Invalid network field: {reason}")
333 }
334 BgpValidationWarning::MalformedAttributeList { reason } => {
335 write!(f, "Malformed attribute list: {reason}")
336 }
337 BgpValidationWarning::PartialAttributeError { attr_type, reason } => {
338 write!(f, "Partial attribute error for {attr_type:?}: {reason}")
339 }
340 BgpValidationWarning::MalformedNlri { nlri_type, reason, .. } => {
341 write!(f, "Malformed NLRI ({nlri_type}): {reason}")
342 }
343 BgpValidationWarning::UnknownRouteRefreshSubtype { subtype } => {
344 write!(f, "Unknown ROUTE-REFRESH message subtype: {subtype}")
345 }
346 BgpValidationWarning::InvalidRouteRefreshLength { subtype, length } => {
347 write!(f, "Invalid ROUTE-REFRESH message length for subtype {subtype}: body is {length} bytes, expected 4")
348 }
349 }
350 }
351}
352
353#[derive(Debug, Clone)]
355pub struct BgpValidationResult<T> {
356 pub value: T,
357 pub warnings: Vec<BgpValidationWarning>,
358}
359
360impl<T> BgpValidationResult<T> {
361 pub fn new(value: T) -> Self {
362 Self {
363 value,
364 warnings: Vec::new(),
365 }
366 }
367
368 pub fn with_warnings(value: T, warnings: Vec<BgpValidationWarning>) -> Self {
369 Self { value, warnings }
370 }
371
372 pub fn add_warning(&mut self, warning: BgpValidationWarning) {
373 self.warnings.push(warning);
374 }
375
376 pub fn has_warnings(&self) -> bool {
377 !self.warnings.is_empty()
378 }
379}