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)]
42pub struct ParserErrorWithBytes {
43 pub error: ParserError,
44 pub bytes: Option<Vec<u8>>,
45}
46
47impl Display for ParserErrorWithBytes {
48 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
49 write!(f, "{}", self.error)
50 }
51}
52
53impl Error for ParserErrorWithBytes {}
54
55impl Display for ParserError {
58 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
59 match self {
60 ParserError::IoError(e) => write!(f, "Error: {e}"),
61 ParserError::EofError(e) => write!(f, "Error: {e}"),
62 ParserError::ParseError(s) => write!(f, "Error: {s}"),
63 ParserError::TruncatedMsg(s) => write!(f, "Error: {s}"),
64 ParserError::Unsupported(s) => write!(f, "Error: {s}"),
65 ParserError::EofExpected => write!(f, "Error: reach end of file"),
66 #[cfg(feature = "oneio")]
67 ParserError::OneIoError(e) => write!(f, "Error: {e}"),
68 ParserError::FilterError(e) => write!(f, "Error: {e}"),
69 ParserError::InvalidLabeledNlriLength => {
70 write!(f, "Error: invalid labeled NLRI length field")
71 }
72 ParserError::TruncatedLabeledNlri => write!(f, "Error: truncated labeled NLRI"),
73 ParserError::TruncatedPrefix => write!(f, "Error: truncated prefix in NLRI"),
74 ParserError::MaxLabelStackDepthExceeded => write!(
75 f,
76 "Error: max label stack depth exceeded without finding BoS bit"
77 ),
78 ParserError::PeerMaxLabelsExceeded => write!(
79 f,
80 "Error: received more labels than peer advertised maximum"
81 ),
82 ParserError::InvalidPrefix => write!(f, "Error: invalid prefix in NLRI"),
83 }
84 }
85}
86
87#[cfg(feature = "oneio")]
88impl From<OneIoError> for ParserErrorWithBytes {
89 fn from(error: OneIoError) -> Self {
90 ParserErrorWithBytes {
91 error: ParserError::OneIoError(error),
92 bytes: None,
93 }
94 }
95}
96
97#[cfg(feature = "oneio")]
98impl From<OneIoError> for ParserError {
99 fn from(error: OneIoError) -> Self {
100 ParserError::OneIoError(error)
101 }
102}
103
104impl From<ParserError> for ParserErrorWithBytes {
105 fn from(error: ParserError) -> Self {
106 ParserErrorWithBytes { error, bytes: None }
107 }
108}
109
110impl From<io::Error> for ParserError {
111 fn from(io_error: io::Error) -> Self {
112 match io_error.kind() {
113 ErrorKind::UnexpectedEof => ParserError::EofError(io_error),
114 _ => ParserError::IoError(io_error),
115 }
116 }
117}
118
119impl From<TryFromPrimitiveError<Bgp4MpType>> for ParserError {
120 fn from(value: TryFromPrimitiveError<Bgp4MpType>) -> Self {
121 ParserError::ParseError(format!("cannot parse bgp4mp subtype: {}", value.number))
122 }
123}
124
125impl From<TryFromPrimitiveError<BgpState>> for ParserError {
126 fn from(value: TryFromPrimitiveError<BgpState>) -> Self {
127 ParserError::ParseError(format!("cannot parse bgp4mp state: {}", value.number))
128 }
129}
130
131impl From<TryFromPrimitiveError<TableDumpV2Type>> for ParserError {
132 fn from(value: TryFromPrimitiveError<TableDumpV2Type>) -> Self {
133 ParserError::ParseError(format!("cannot parse table dump v2 type: {}", value.number))
134 }
135}
136
137impl From<TryFromPrimitiveError<EntryType>> for ParserError {
138 fn from(value: TryFromPrimitiveError<EntryType>) -> Self {
139 ParserError::ParseError(format!("cannot parse entry type: {}", value.number))
140 }
141}
142
143impl From<TryFromPrimitiveError<Afi>> for ParserError {
144 fn from(value: TryFromPrimitiveError<Afi>) -> Self {
145 ParserError::ParseError(format!("Unknown AFI type: {}", value.number))
146 }
147}
148
149impl From<TryFromPrimitiveError<Safi>> for ParserError {
150 fn from(value: TryFromPrimitiveError<Safi>) -> Self {
151 ParserError::ParseError(format!("Unknown SAFI type: {}", value.number))
152 }
153}
154
155#[derive(Debug, Clone, PartialEq, Eq)]
158pub enum BgpValidationWarning {
159 AttributeFlagsError {
161 attr_type: AttrType,
162 expected_flags: u8,
163 actual_flags: u8,
164 },
165 AttributeLengthError {
167 attr_type: AttrType,
168 expected_length: Option<usize>,
169 actual_length: usize,
170 },
171 MissingWellKnownAttribute { attr_type: AttrType },
173 UnrecognizedWellKnownAttribute { attr_type_code: u8 },
175 InvalidOriginAttribute { value: u8 },
177 InvalidNextHopAttribute { reason: String },
179 MalformedAsPath { reason: String },
181 OptionalAttributeError { attr_type: AttrType, reason: String },
183 DuplicateAttribute { attr_type: AttrType },
185 InvalidNetworkField { reason: String },
187 MalformedAttributeList { reason: String },
189 PartialAttributeError { attr_type: AttrType, reason: String },
191}
192
193impl Display for BgpValidationWarning {
194 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
195 match self {
196 BgpValidationWarning::AttributeFlagsError { attr_type, expected_flags, actual_flags } => {
197 write!(f, "Attribute flags error for {attr_type:?}: expected 0x{expected_flags:02x}, got 0x{actual_flags:02x}")
198 }
199 BgpValidationWarning::AttributeLengthError { attr_type, expected_length, actual_length } => {
200 match expected_length {
201 Some(expected) => write!(f, "Attribute length error for {attr_type:?}: expected {expected}, got {actual_length}"),
202 None => write!(f, "Attribute length error for {attr_type:?}: invalid length {actual_length}"),
203 }
204 }
205 BgpValidationWarning::MissingWellKnownAttribute { attr_type } => {
206 write!(f, "Missing well-known mandatory attribute: {attr_type:?}")
207 }
208 BgpValidationWarning::UnrecognizedWellKnownAttribute { attr_type_code } => {
209 write!(f, "Unrecognized well-known attribute: type code {attr_type_code}")
210 }
211 BgpValidationWarning::InvalidOriginAttribute { value } => {
212 write!(f, "Invalid origin attribute value: {value}")
213 }
214 BgpValidationWarning::InvalidNextHopAttribute { reason } => {
215 write!(f, "Invalid next hop attribute: {reason}")
216 }
217 BgpValidationWarning::MalformedAsPath { reason } => {
218 write!(f, "Malformed AS_PATH: {reason}")
219 }
220 BgpValidationWarning::OptionalAttributeError { attr_type, reason } => {
221 write!(f, "Optional attribute error for {attr_type:?}: {reason}")
222 }
223 BgpValidationWarning::DuplicateAttribute { attr_type } => {
224 write!(f, "Duplicate attribute: {attr_type:?}")
225 }
226 BgpValidationWarning::InvalidNetworkField { reason } => {
227 write!(f, "Invalid network field: {reason}")
228 }
229 BgpValidationWarning::MalformedAttributeList { reason } => {
230 write!(f, "Malformed attribute list: {reason}")
231 }
232 BgpValidationWarning::PartialAttributeError { attr_type, reason } => {
233 write!(f, "Partial attribute error for {attr_type:?}: {reason}")
234 }
235 }
236 }
237}
238
239#[derive(Debug, Clone)]
241pub struct BgpValidationResult<T> {
242 pub value: T,
243 pub warnings: Vec<BgpValidationWarning>,
244}
245
246impl<T> BgpValidationResult<T> {
247 pub fn new(value: T) -> Self {
248 Self {
249 value,
250 warnings: Vec::new(),
251 }
252 }
253
254 pub fn with_warnings(value: T, warnings: Vec<BgpValidationWarning>) -> Self {
255 Self { value, warnings }
256 }
257
258 pub fn add_warning(&mut self, warning: BgpValidationWarning) {
259 self.warnings.push(warning);
260 }
261
262 pub fn has_warnings(&self) -> bool {
263 !self.warnings.is_empty()
264 }
265}