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 OversizedRecord {
26 length: u32,
28 },
29 FilterError(String),
30 InvalidLabeledNlriLength,
33 TruncatedLabeledNlri,
35 TruncatedPrefix,
37 MaxLabelStackDepthExceeded,
39 PeerMaxLabelsExceeded,
42 InvalidPrefix,
44}
45
46impl Error for ParserError {}
47
48#[derive(Debug, Clone, PartialEq, Eq)]
55#[non_exhaustive]
56pub enum EncodingError {
57 ValueTooLarge {
63 field: &'static str,
64 actual: usize,
65 max: usize,
66 },
67 Unencodable { field: &'static str, reason: String },
71}
72
73impl EncodingError {
74 pub(crate) fn too_large(field: &'static str, actual: usize, max: usize) -> Self {
75 EncodingError::ValueTooLarge { field, actual, max }
76 }
77
78 #[cfg(feature = "parser")]
79 pub(crate) fn unencodable(field: &'static str, reason: impl Into<String>) -> Self {
80 EncodingError::Unencodable {
81 field,
82 reason: reason.into(),
83 }
84 }
85}
86
87pub(crate) fn check_max(
93 field: &'static str,
94 actual: usize,
95 max: usize,
96) -> Result<usize, EncodingError> {
97 if actual > max {
98 return Err(EncodingError::too_large(field, actual, max));
99 }
100 Ok(actual)
101}
102
103impl Display for EncodingError {
104 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105 match self {
106 EncodingError::ValueTooLarge { field, actual, max } => write!(
107 f,
108 "encoding error: {field} ({actual}) exceeds maximum ({max})"
109 ),
110 EncodingError::Unencodable { field, reason } => {
111 write!(f, "encoding error: {field} cannot be encoded: {reason}")
112 }
113 }
114 }
115}
116
117impl Error for EncodingError {}
118
119#[derive(Debug)]
120pub struct ParserErrorWithBytes {
121 pub error: ParserError,
122 pub bytes: Option<Vec<u8>>,
123}
124
125impl Display for ParserErrorWithBytes {
126 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
127 write!(f, "{}", self.error)
128 }
129}
130
131impl Error for ParserErrorWithBytes {}
132
133impl Display for ParserError {
136 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
137 match self {
138 ParserError::IoError(e) => write!(f, "Error: {e}"),
139 ParserError::EofError(e) => write!(f, "Error: {e}"),
140 ParserError::ParseError(s) => write!(f, "Error: {s}"),
141 ParserError::TruncatedMsg(s) => write!(f, "Error: {s}"),
142 ParserError::Unsupported(s) => write!(f, "Error: {s}"),
143 ParserError::OversizedRecord { length } => {
144 write!(f, "Error: MRT message too large: {length} bytes")
145 }
146 ParserError::EofExpected => write!(f, "Error: reach end of file"),
147 #[cfg(feature = "oneio")]
148 ParserError::OneIoError(e) => write!(f, "Error: {e}"),
149 ParserError::FilterError(e) => write!(f, "Error: {e}"),
150 ParserError::InvalidLabeledNlriLength => {
151 write!(f, "Error: invalid labeled NLRI length field")
152 }
153 ParserError::TruncatedLabeledNlri => write!(f, "Error: truncated labeled NLRI"),
154 ParserError::TruncatedPrefix => write!(f, "Error: truncated prefix in NLRI"),
155 ParserError::MaxLabelStackDepthExceeded => write!(
156 f,
157 "Error: max label stack depth exceeded without finding BoS bit"
158 ),
159 ParserError::PeerMaxLabelsExceeded => write!(
160 f,
161 "Error: received more labels than peer advertised maximum"
162 ),
163 ParserError::InvalidPrefix => write!(f, "Error: invalid prefix in NLRI"),
164 }
165 }
166}
167
168#[cfg(feature = "oneio")]
169impl From<OneIoError> for ParserErrorWithBytes {
170 fn from(error: OneIoError) -> Self {
171 ParserErrorWithBytes {
172 error: ParserError::OneIoError(error),
173 bytes: None,
174 }
175 }
176}
177
178#[cfg(feature = "oneio")]
179impl From<OneIoError> for ParserError {
180 fn from(error: OneIoError) -> Self {
181 ParserError::OneIoError(error)
182 }
183}
184
185impl From<ParserError> for ParserErrorWithBytes {
186 fn from(error: ParserError) -> Self {
187 ParserErrorWithBytes { error, bytes: None }
188 }
189}
190
191impl From<io::Error> for ParserError {
192 fn from(io_error: io::Error) -> Self {
193 match io_error.kind() {
194 ErrorKind::UnexpectedEof => ParserError::EofError(io_error),
195 _ => ParserError::IoError(io_error),
196 }
197 }
198}
199
200impl From<TryFromPrimitiveError<Bgp4MpType>> for ParserError {
201 fn from(value: TryFromPrimitiveError<Bgp4MpType>) -> Self {
202 ParserError::ParseError(format!("cannot parse bgp4mp subtype: {}", value.number))
203 }
204}
205
206impl From<TryFromPrimitiveError<BgpState>> for ParserError {
207 fn from(value: TryFromPrimitiveError<BgpState>) -> Self {
208 ParserError::ParseError(format!("cannot parse bgp4mp state: {}", value.number))
209 }
210}
211
212impl From<TryFromPrimitiveError<TableDumpV2Type>> for ParserError {
213 fn from(value: TryFromPrimitiveError<TableDumpV2Type>) -> Self {
214 ParserError::ParseError(format!("cannot parse table dump v2 type: {}", value.number))
215 }
216}
217
218impl From<TryFromPrimitiveError<EntryType>> for ParserError {
219 fn from(value: TryFromPrimitiveError<EntryType>) -> Self {
220 ParserError::ParseError(format!("cannot parse entry type: {}", value.number))
221 }
222}
223
224impl From<TryFromPrimitiveError<Afi>> for ParserError {
225 fn from(value: TryFromPrimitiveError<Afi>) -> Self {
226 ParserError::ParseError(format!("Unknown AFI type: {}", value.number))
227 }
228}
229
230impl From<TryFromPrimitiveError<Safi>> for ParserError {
231 fn from(value: TryFromPrimitiveError<Safi>) -> Self {
232 ParserError::ParseError(format!("Unknown SAFI type: {}", value.number))
233 }
234}
235
236#[derive(Debug, Clone, PartialEq, Eq)]
242#[cfg_attr(feature = "serde", derive(serde::Serialize))]
243#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS), ts(export))]
244#[non_exhaustive]
245pub enum BgpValidationWarning {
246 AttributeFlagsError {
248 attr_type: AttrType,
249 expected_flags: u8,
250 actual_flags: u8,
251 },
252 AttributeLengthError {
254 attr_type: AttrType,
255 expected_length: Option<usize>,
256 actual_length: usize,
257 },
258 MissingWellKnownAttribute { attr_type: AttrType },
260 UnrecognizedWellKnownAttribute { attr_type_code: u8 },
262 InvalidOriginAttribute { value: u8 },
264 InvalidNextHopAttribute { reason: String },
266 MalformedAsPath { reason: String },
268 OptionalAttributeError { attr_type: AttrType, reason: String },
270 DuplicateAttribute { attr_type: AttrType },
272 InvalidNetworkField { reason: String },
274 MalformedAttributeList { reason: String },
276 PartialAttributeError { attr_type: AttrType, reason: String },
278 MalformedNlri {
288 nlri_type: &'static str,
290 reason: String,
292 raw_bytes: Vec<u8>,
294 },
295 UnknownRouteRefreshSubtype { subtype: u8 },
299 InvalidRouteRefreshLength {
305 subtype: u8,
306 length: usize,
308 },
309}
310
311impl Display for BgpValidationWarning {
312 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
313 match self {
314 BgpValidationWarning::AttributeFlagsError { attr_type, expected_flags, actual_flags } => {
315 write!(f, "Attribute flags error for {attr_type:?}: expected 0x{expected_flags:02x}, got 0x{actual_flags:02x}")
316 }
317 BgpValidationWarning::AttributeLengthError { attr_type, expected_length, actual_length } => {
318 match expected_length {
319 Some(expected) => write!(f, "Attribute length error for {attr_type:?}: expected {expected}, got {actual_length}"),
320 None => write!(f, "Attribute length error for {attr_type:?}: invalid length {actual_length}"),
321 }
322 }
323 BgpValidationWarning::MissingWellKnownAttribute { attr_type } => {
324 write!(f, "Missing well-known mandatory attribute: {attr_type:?}")
325 }
326 BgpValidationWarning::UnrecognizedWellKnownAttribute { attr_type_code } => {
327 write!(f, "Unrecognized well-known attribute: type code {attr_type_code}")
328 }
329 BgpValidationWarning::InvalidOriginAttribute { value } => {
330 write!(f, "Invalid origin attribute value: {value}")
331 }
332 BgpValidationWarning::InvalidNextHopAttribute { reason } => {
333 write!(f, "Invalid next hop attribute: {reason}")
334 }
335 BgpValidationWarning::MalformedAsPath { reason } => {
336 write!(f, "Malformed AS_PATH: {reason}")
337 }
338 BgpValidationWarning::OptionalAttributeError { attr_type, reason } => {
339 write!(f, "Optional attribute error for {attr_type:?}: {reason}")
340 }
341 BgpValidationWarning::DuplicateAttribute { attr_type } => {
342 write!(f, "Duplicate attribute: {attr_type:?}")
343 }
344 BgpValidationWarning::InvalidNetworkField { reason } => {
345 write!(f, "Invalid network field: {reason}")
346 }
347 BgpValidationWarning::MalformedAttributeList { reason } => {
348 write!(f, "Malformed attribute list: {reason}")
349 }
350 BgpValidationWarning::PartialAttributeError { attr_type, reason } => {
351 write!(f, "Partial attribute error for {attr_type:?}: {reason}")
352 }
353 BgpValidationWarning::MalformedNlri { nlri_type, reason, .. } => {
354 write!(f, "Malformed NLRI ({nlri_type}): {reason}")
355 }
356 BgpValidationWarning::UnknownRouteRefreshSubtype { subtype } => {
357 write!(f, "Unknown ROUTE-REFRESH message subtype: {subtype}")
358 }
359 BgpValidationWarning::InvalidRouteRefreshLength { subtype, length } => {
360 write!(f, "Invalid ROUTE-REFRESH message length for subtype {subtype}: body is {length} bytes, expected 4")
361 }
362 }
363 }
364}
365
366#[derive(Debug, Clone)]
368pub struct BgpValidationResult<T> {
369 pub value: T,
370 pub warnings: Vec<BgpValidationWarning>,
371}
372
373impl<T> BgpValidationResult<T> {
374 pub fn new(value: T) -> Self {
375 Self {
376 value,
377 warnings: Vec::new(),
378 }
379 }
380
381 pub fn with_warnings(value: T, warnings: Vec<BgpValidationWarning>) -> Self {
382 Self { value, warnings }
383 }
384
385 pub fn add_warning(&mut self, warning: BgpValidationWarning) {
386 self.warnings.push(warning);
387 }
388
389 pub fn has_warnings(&self) -> bool {
390 !self.warnings.is_empty()
391 }
392}