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}
24
25impl Error for ParserError {}
26
27#[derive(Debug)]
28pub struct ParserErrorWithBytes {
29 pub error: ParserError,
30 pub bytes: Option<Vec<u8>>,
31}
32
33impl Display for ParserErrorWithBytes {
34 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
35 write!(f, "{}", self.error)
36 }
37}
38
39impl Error for ParserErrorWithBytes {}
40
41impl Display for ParserError {
44 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45 match self {
46 ParserError::IoError(e) => write!(f, "Error: {e}"),
47 ParserError::EofError(e) => write!(f, "Error: {e}"),
48 ParserError::ParseError(s) => write!(f, "Error: {s}"),
49 ParserError::TruncatedMsg(s) => write!(f, "Error: {s}"),
50 ParserError::Unsupported(s) => write!(f, "Error: {s}"),
51 ParserError::EofExpected => write!(f, "Error: reach end of file"),
52 #[cfg(feature = "oneio")]
53 ParserError::OneIoError(e) => write!(f, "Error: {e}"),
54 ParserError::FilterError(e) => write!(f, "Error: {e}"),
55 }
56 }
57}
58
59#[cfg(feature = "oneio")]
60impl From<OneIoError> for ParserErrorWithBytes {
61 fn from(error: OneIoError) -> Self {
62 ParserErrorWithBytes {
63 error: ParserError::OneIoError(error),
64 bytes: None,
65 }
66 }
67}
68
69#[cfg(feature = "oneio")]
70impl From<OneIoError> for ParserError {
71 fn from(error: OneIoError) -> Self {
72 ParserError::OneIoError(error)
73 }
74}
75
76impl From<ParserError> for ParserErrorWithBytes {
77 fn from(error: ParserError) -> Self {
78 ParserErrorWithBytes { error, bytes: None }
79 }
80}
81
82impl From<io::Error> for ParserError {
83 fn from(io_error: io::Error) -> Self {
84 match io_error.kind() {
85 ErrorKind::UnexpectedEof => ParserError::EofError(io_error),
86 _ => ParserError::IoError(io_error),
87 }
88 }
89}
90
91impl From<TryFromPrimitiveError<Bgp4MpType>> for ParserError {
92 fn from(value: TryFromPrimitiveError<Bgp4MpType>) -> Self {
93 ParserError::ParseError(format!("cannot parse bgp4mp subtype: {}", value.number))
94 }
95}
96
97impl From<TryFromPrimitiveError<BgpState>> for ParserError {
98 fn from(value: TryFromPrimitiveError<BgpState>) -> Self {
99 ParserError::ParseError(format!("cannot parse bgp4mp state: {}", value.number))
100 }
101}
102
103impl From<TryFromPrimitiveError<TableDumpV2Type>> for ParserError {
104 fn from(value: TryFromPrimitiveError<TableDumpV2Type>) -> Self {
105 ParserError::ParseError(format!("cannot parse table dump v2 type: {}", value.number))
106 }
107}
108
109impl From<TryFromPrimitiveError<EntryType>> for ParserError {
110 fn from(value: TryFromPrimitiveError<EntryType>) -> Self {
111 ParserError::ParseError(format!("cannot parse entry type: {}", value.number))
112 }
113}
114
115impl From<TryFromPrimitiveError<Afi>> for ParserError {
116 fn from(value: TryFromPrimitiveError<Afi>) -> Self {
117 ParserError::ParseError(format!("Unknown AFI type: {}", value.number))
118 }
119}
120
121impl From<TryFromPrimitiveError<Safi>> for ParserError {
122 fn from(value: TryFromPrimitiveError<Safi>) -> Self {
123 ParserError::ParseError(format!("Unknown SAFI type: {}", value.number))
124 }
125}
126
127#[derive(Debug, Clone, PartialEq, Eq)]
130pub enum BgpValidationWarning {
131 AttributeFlagsError {
133 attr_type: AttrType,
134 expected_flags: u8,
135 actual_flags: u8,
136 },
137 AttributeLengthError {
139 attr_type: AttrType,
140 expected_length: Option<usize>,
141 actual_length: usize,
142 },
143 MissingWellKnownAttribute { attr_type: AttrType },
145 UnrecognizedWellKnownAttribute { attr_type_code: u8 },
147 InvalidOriginAttribute { value: u8 },
149 InvalidNextHopAttribute { reason: String },
151 MalformedAsPath { reason: String },
153 OptionalAttributeError { attr_type: AttrType, reason: String },
155 DuplicateAttribute { attr_type: AttrType },
157 InvalidNetworkField { reason: String },
159 MalformedAttributeList { reason: String },
161 PartialAttributeError { attr_type: AttrType, reason: String },
163}
164
165impl Display for BgpValidationWarning {
166 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
167 match self {
168 BgpValidationWarning::AttributeFlagsError { attr_type, expected_flags, actual_flags } => {
169 write!(f, "Attribute flags error for {attr_type:?}: expected 0x{expected_flags:02x}, got 0x{actual_flags:02x}")
170 }
171 BgpValidationWarning::AttributeLengthError { attr_type, expected_length, actual_length } => {
172 match expected_length {
173 Some(expected) => write!(f, "Attribute length error for {attr_type:?}: expected {expected}, got {actual_length}"),
174 None => write!(f, "Attribute length error for {attr_type:?}: invalid length {actual_length}"),
175 }
176 }
177 BgpValidationWarning::MissingWellKnownAttribute { attr_type } => {
178 write!(f, "Missing well-known mandatory attribute: {attr_type:?}")
179 }
180 BgpValidationWarning::UnrecognizedWellKnownAttribute { attr_type_code } => {
181 write!(f, "Unrecognized well-known attribute: type code {attr_type_code}")
182 }
183 BgpValidationWarning::InvalidOriginAttribute { value } => {
184 write!(f, "Invalid origin attribute value: {value}")
185 }
186 BgpValidationWarning::InvalidNextHopAttribute { reason } => {
187 write!(f, "Invalid next hop attribute: {reason}")
188 }
189 BgpValidationWarning::MalformedAsPath { reason } => {
190 write!(f, "Malformed AS_PATH: {reason}")
191 }
192 BgpValidationWarning::OptionalAttributeError { attr_type, reason } => {
193 write!(f, "Optional attribute error for {attr_type:?}: {reason}")
194 }
195 BgpValidationWarning::DuplicateAttribute { attr_type } => {
196 write!(f, "Duplicate attribute: {attr_type:?}")
197 }
198 BgpValidationWarning::InvalidNetworkField { reason } => {
199 write!(f, "Invalid network field: {reason}")
200 }
201 BgpValidationWarning::MalformedAttributeList { reason } => {
202 write!(f, "Malformed attribute list: {reason}")
203 }
204 BgpValidationWarning::PartialAttributeError { attr_type, reason } => {
205 write!(f, "Partial attribute error for {attr_type:?}: {reason}")
206 }
207 }
208 }
209}
210
211#[derive(Debug, Clone)]
213pub struct BgpValidationResult<T> {
214 pub value: T,
215 pub warnings: Vec<BgpValidationWarning>,
216}
217
218impl<T> BgpValidationResult<T> {
219 pub fn new(value: T) -> Self {
220 Self {
221 value,
222 warnings: Vec::new(),
223 }
224 }
225
226 pub fn with_warnings(value: T, warnings: Vec<BgpValidationWarning>) -> Self {
227 Self { value, warnings }
228 }
229
230 pub fn add_warning(&mut self, warning: BgpValidationWarning) {
231 self.warnings.push(warning);
232 }
233
234 pub fn has_warnings(&self) -> bool {
235 !self.warnings.is_empty()
236 }
237}