1use num_traits::FromPrimitive;
6use serde::Serialize;
7use std::error::Error;
8use std::fmt::{Display, Formatter};
9
10#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
12pub enum BgpErrorCodeParsingError {
13 UnknownCode(u8),
14 UnknownSubcode(u8),
15 DeprecatedCode(u8),
16 DeprecatedSubcode(u8),
17}
18
19impl Display for BgpErrorCodeParsingError {
20 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
21 match self {
22 BgpErrorCodeParsingError::UnknownCode(v) => {
23 write!(f, "unknown BGP error code {}", v)
24 }
25 BgpErrorCodeParsingError::UnknownSubcode(v) => {
26 write!(f, "unknown BGP error subcode {}", v)
27 }
28 BgpErrorCodeParsingError::DeprecatedCode(v) => {
29 write!(f, "deprecated BGP error code {}", v)
30 }
31 BgpErrorCodeParsingError::DeprecatedSubcode(v) => {
32 write!(f, "deprecated BGP error subcode {}", v)
33 }
34 }
35 }
36}
37
38impl Error for BgpErrorCodeParsingError {}
39
40pub fn parse_error_codes(
42 error_code: &u8,
43 error_subcode: &u8,
44) -> Result<BgpError, BgpErrorCodeParsingError> {
45 match error_code {
46 0 => Ok(BgpError::Reserved),
47 1 => match MessageHeaderErrorSubcode::from_u8(*error_subcode) {
48 Some(v) => Ok(BgpError::MessageHeaderError(v)),
49 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
50 },
51 2 => {
52 if [5, 8, 9, 10].contains(error_subcode) {
53 return Err(BgpErrorCodeParsingError::DeprecatedSubcode(*error_subcode));
54 }
55 match OpenMessageErrorSubcode::from_u8(*error_subcode) {
56 Some(v) => Ok(BgpError::OpenMessageError(v)),
57 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
58 }
59 }
60 3 => {
61 if [7].contains(error_subcode) {
62 return Err(BgpErrorCodeParsingError::DeprecatedSubcode(*error_subcode));
63 }
64 match UpdateMessageErrorSubcode::from_u8(*error_subcode) {
65 Some(v) => Ok(BgpError::UpdateMessageError(v)),
66 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
67 }
68 }
69 4 => Ok(BgpError::HoldTimerExpired),
70 5 => match BgpFiniteStateMachineErrorSubcode::from_u8(*error_subcode) {
71 Some(v) => Ok(BgpError::BgpFiniteStateMachineError(v)),
72 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
73 },
74 6 => match BgpCeaseNotificationMessageSubcode::from_u8(*error_subcode) {
75 Some(v) => Ok(BgpError::BgpCeaseNotification(v)),
76 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
77 },
78 7 => match BgpRouteRefreshMessageErrorSubcode::from_u8(*error_subcode) {
79 Some(v) => Ok(BgpError::BgpRouteFreshMessageError(v)),
80 None => Err(BgpErrorCodeParsingError::UnknownSubcode(*error_subcode)),
81 },
82 v => Err(BgpErrorCodeParsingError::UnknownCode(*v)),
83 }
84}
85
86#[allow(non_camel_case_types)]
90#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
91pub enum BgpError {
92 Reserved,
93 MessageHeaderError(MessageHeaderErrorSubcode),
94 OpenMessageError(OpenMessageErrorSubcode),
95 UpdateMessageError(UpdateMessageErrorSubcode),
96 HoldTimerExpired,
97 BgpFiniteStateMachineError(BgpFiniteStateMachineErrorSubcode),
98 BgpCeaseNotification(BgpCeaseNotificationMessageSubcode),
99 BgpRouteFreshMessageError(BgpRouteRefreshMessageErrorSubcode),
100}
101
102#[allow(non_camel_case_types)]
108#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
109pub enum MessageHeaderErrorSubcode {
110 UNSPECIFIC = 0,
111 CONNECTION_NOT_SYNCHRONIZED = 1,
112 BAD_MESSAGE_LENGTH = 2,
113 BAD_MESSAGE_TYPE = 3,
114 }
116
117#[allow(non_camel_case_types)]
123#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
124pub enum OpenMessageErrorSubcode {
125 UNSPECIFIC = 0,
126 UNSUPPORTED_VERSION_NUMBER = 1,
127 BAD_PEER_AS = 2,
128 BAD_BGP_IDENTIFIER = 3,
129 UNSUPPORTED_OPTIONAL_PARAMETER = 4,
130 UNACCEPTABLE_HOLD_TIME = 6,
132 UNSUPPORTED_CAPACITY = 7,
133 ROLE_MISMATCH = 11,
137 }
139
140#[allow(non_camel_case_types)]
146#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
147pub enum UpdateMessageErrorSubcode {
148 UNSPECIFIC = 0,
149 MALFORMED_ATTRIBUTE_LIST = 1,
150 UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE = 2,
151 MISSING_WELL_KNOWN_ATTRIBUTE = 3,
152 ATTRIBUTE_FLAGS_ERROR = 4,
153 ATTRIBUTE_LENGTH_ERROR = 5,
154 INVALID_ORIGIN_ERROR = 6,
155 INVALID_NEXT_HOP_ATTRIBUTE = 8,
157 OPTIONAL_ATTRIBUTE_ERROR = 9,
158 INVALID_NETWORK_FIELD = 10,
159 MALFORMED_AS_PATH = 11,
160 }
162
163#[allow(non_camel_case_types)]
169#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
170pub enum BgpFiniteStateMachineErrorSubcode {
171 UNSPECIFIED = 0,
172 RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_State = 1,
173 RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE = 2,
174 RECEIVE_UNEXPECTED_MESSAGE_IN_ESTABLISHED_STATE = 3,
175 }
177
178#[allow(non_camel_case_types)]
184#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
185pub enum BgpCeaseNotificationMessageSubcode {
186 RESERVED = 0,
187 MAXIMUM_NUMBER_OF_PREFIXES_REACHED = 1,
188 ADMINISTRATIVE_SHUTDOWN = 2,
189 PEER_DE_CONFIGURED = 3,
190 ADMINISTRATIVE_RESET = 4,
191 CONNECTION_REJECTED = 5,
192 OTHER_CONFIGURATION_CHANGE = 6,
193 CONNECTION_COLLISION_RESOLUTION = 7,
194 OUT_OF_RESOURCES = 8,
195 HARD_RESET = 9,
196 BFD_DOWN = 10, }
199
200#[allow(non_camel_case_types)]
206#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
207pub enum BgpRouteRefreshMessageErrorSubcode {
208 RESERVED = 0,
209 INVALID_MESSAGE_LENGTH = 1,
210 }
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_parsing() {
219 let mut error_code: u8;
220 let mut error_subcode: u8;
221 error_code = 0;
222 error_subcode = 0;
223 assert_eq!(
224 parse_error_codes(&error_code, &error_subcode),
225 Ok(BgpError::Reserved)
226 );
227
228 error_code = 1;
229 error_subcode = 0;
230 assert_eq!(
231 parse_error_codes(&error_code, &error_subcode),
232 Ok(BgpError::MessageHeaderError(
233 MessageHeaderErrorSubcode::UNSPECIFIC
234 ))
235 );
236 error_subcode = 1;
237 assert_eq!(
238 parse_error_codes(&error_code, &error_subcode),
239 Ok(BgpError::MessageHeaderError(
240 MessageHeaderErrorSubcode::CONNECTION_NOT_SYNCHRONIZED
241 ))
242 );
243 error_subcode = 2;
244 assert_eq!(
245 parse_error_codes(&error_code, &error_subcode),
246 Ok(BgpError::MessageHeaderError(
247 MessageHeaderErrorSubcode::BAD_MESSAGE_LENGTH
248 ))
249 );
250 error_subcode = 3;
251 assert_eq!(
252 parse_error_codes(&error_code, &error_subcode),
253 Ok(BgpError::MessageHeaderError(
254 MessageHeaderErrorSubcode::BAD_MESSAGE_TYPE
255 ))
256 );
257 error_subcode = 4;
258 assert_eq!(
259 parse_error_codes(&error_code, &error_subcode),
260 Err(BgpErrorCodeParsingError::UnknownSubcode(4))
261 );
262
263 error_code = 2;
264 error_subcode = 0;
265 assert_eq!(
266 parse_error_codes(&error_code, &error_subcode),
267 Ok(BgpError::OpenMessageError(
268 OpenMessageErrorSubcode::UNSPECIFIC
269 ))
270 );
271 error_subcode = 1;
272 assert_eq!(
273 parse_error_codes(&error_code, &error_subcode),
274 Ok(BgpError::OpenMessageError(
275 OpenMessageErrorSubcode::UNSUPPORTED_VERSION_NUMBER
276 ))
277 );
278 error_subcode = 2;
279 assert_eq!(
280 parse_error_codes(&error_code, &error_subcode),
281 Ok(BgpError::OpenMessageError(
282 OpenMessageErrorSubcode::BAD_PEER_AS
283 ))
284 );
285 error_subcode = 3;
286 assert_eq!(
287 parse_error_codes(&error_code, &error_subcode),
288 Ok(BgpError::OpenMessageError(
289 OpenMessageErrorSubcode::BAD_BGP_IDENTIFIER
290 ))
291 );
292 error_subcode = 4;
293 assert_eq!(
294 parse_error_codes(&error_code, &error_subcode),
295 Ok(BgpError::OpenMessageError(
296 OpenMessageErrorSubcode::UNSUPPORTED_OPTIONAL_PARAMETER
297 ))
298 );
299 error_subcode = 6;
300 assert_eq!(
301 parse_error_codes(&error_code, &error_subcode),
302 Ok(BgpError::OpenMessageError(
303 OpenMessageErrorSubcode::UNACCEPTABLE_HOLD_TIME
304 ))
305 );
306 error_subcode = 7;
307 assert_eq!(
308 parse_error_codes(&error_code, &error_subcode),
309 Ok(BgpError::OpenMessageError(
310 OpenMessageErrorSubcode::UNSUPPORTED_CAPACITY
311 ))
312 );
313 error_subcode = 11;
314 assert_eq!(
315 parse_error_codes(&error_code, &error_subcode),
316 Ok(BgpError::OpenMessageError(
317 OpenMessageErrorSubcode::ROLE_MISMATCH
318 ))
319 );
320 for n in [5, 8, 9, 10] {
322 error_subcode = n as u8;
323 assert_eq!(
324 parse_error_codes(&error_code, &error_subcode),
325 Err(BgpErrorCodeParsingError::DeprecatedSubcode(error_subcode))
326 );
327 }
328 error_subcode = 12;
329 assert_eq!(
330 parse_error_codes(&error_code, &error_subcode),
331 Err(BgpErrorCodeParsingError::UnknownSubcode(12))
332 );
333
334 error_code = 3;
335 error_subcode = 0;
336 assert_eq!(
337 parse_error_codes(&error_code, &error_subcode),
338 Ok(BgpError::UpdateMessageError(
339 UpdateMessageErrorSubcode::UNSPECIFIC
340 ))
341 );
342 error_subcode = 1;
343 assert_eq!(
344 parse_error_codes(&error_code, &error_subcode),
345 Ok(BgpError::UpdateMessageError(
346 UpdateMessageErrorSubcode::MALFORMED_ATTRIBUTE_LIST
347 ))
348 );
349 error_subcode = 2;
350 assert_eq!(
351 parse_error_codes(&error_code, &error_subcode),
352 Ok(BgpError::UpdateMessageError(
353 UpdateMessageErrorSubcode::UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE
354 ))
355 );
356 error_subcode = 3;
357 assert_eq!(
358 parse_error_codes(&error_code, &error_subcode),
359 Ok(BgpError::UpdateMessageError(
360 UpdateMessageErrorSubcode::MISSING_WELL_KNOWN_ATTRIBUTE
361 ))
362 );
363 error_subcode = 4;
364 assert_eq!(
365 parse_error_codes(&error_code, &error_subcode),
366 Ok(BgpError::UpdateMessageError(
367 UpdateMessageErrorSubcode::ATTRIBUTE_FLAGS_ERROR
368 ))
369 );
370 error_subcode = 5;
371 assert_eq!(
372 parse_error_codes(&error_code, &error_subcode),
373 Ok(BgpError::UpdateMessageError(
374 UpdateMessageErrorSubcode::ATTRIBUTE_LENGTH_ERROR
375 ))
376 );
377 error_subcode = 6;
378 assert_eq!(
379 parse_error_codes(&error_code, &error_subcode),
380 Ok(BgpError::UpdateMessageError(
381 UpdateMessageErrorSubcode::INVALID_ORIGIN_ERROR
382 ))
383 );
384 error_subcode = 8;
385 assert_eq!(
386 parse_error_codes(&error_code, &error_subcode),
387 Ok(BgpError::UpdateMessageError(
388 UpdateMessageErrorSubcode::INVALID_NEXT_HOP_ATTRIBUTE
389 ))
390 );
391 error_subcode = 9;
392 assert_eq!(
393 parse_error_codes(&error_code, &error_subcode),
394 Ok(BgpError::UpdateMessageError(
395 UpdateMessageErrorSubcode::OPTIONAL_ATTRIBUTE_ERROR
396 ))
397 );
398 error_subcode = 10;
399 assert_eq!(
400 parse_error_codes(&error_code, &error_subcode),
401 Ok(BgpError::UpdateMessageError(
402 UpdateMessageErrorSubcode::INVALID_NETWORK_FIELD
403 ))
404 );
405 error_subcode = 11;
406 assert_eq!(
407 parse_error_codes(&error_code, &error_subcode),
408 Ok(BgpError::UpdateMessageError(
409 UpdateMessageErrorSubcode::MALFORMED_AS_PATH
410 ))
411 );
412 for n in [7] {
414 error_subcode = n as u8;
415 assert_eq!(
416 parse_error_codes(&error_code, &error_subcode),
417 Err(BgpErrorCodeParsingError::DeprecatedSubcode(error_subcode))
418 );
419 }
420 error_subcode = 12;
421 assert_eq!(
422 parse_error_codes(&error_code, &error_subcode),
423 Err(BgpErrorCodeParsingError::UnknownSubcode(12))
424 );
425
426 error_code = 4;
427 error_subcode = 0;
428 assert_eq!(
429 parse_error_codes(&error_code, &error_subcode),
430 Ok(BgpError::HoldTimerExpired)
431 );
432 error_subcode = 1;
434 assert_eq!(
435 parse_error_codes(&error_code, &error_subcode),
436 Ok(BgpError::HoldTimerExpired)
437 );
438
439 error_code = 5;
440 error_subcode = 0;
441 assert_eq!(
442 parse_error_codes(&error_code, &error_subcode),
443 Ok(BgpError::BgpFiniteStateMachineError(
444 BgpFiniteStateMachineErrorSubcode::UNSPECIFIED
445 ))
446 );
447 error_subcode = 1;
448 assert_eq!(
449 parse_error_codes(&error_code, &error_subcode),
450 Ok(BgpError::BgpFiniteStateMachineError(
451 BgpFiniteStateMachineErrorSubcode::RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_State
452 ))
453 );
454 error_subcode = 2;
455 assert_eq!(
456 parse_error_codes(&error_code, &error_subcode),
457 Ok(BgpError::BgpFiniteStateMachineError(
458 BgpFiniteStateMachineErrorSubcode::RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE
459 ))
460 );
461 error_subcode = 3;
462 assert_eq!(
463 parse_error_codes(&error_code, &error_subcode),
464 Ok(BgpError::BgpFiniteStateMachineError(
465 BgpFiniteStateMachineErrorSubcode::RECEIVE_UNEXPECTED_MESSAGE_IN_ESTABLISHED_STATE
466 ))
467 );
468 error_subcode = 4;
469 assert_eq!(
470 parse_error_codes(&error_code, &error_subcode),
471 Err(BgpErrorCodeParsingError::UnknownSubcode(4))
472 );
473
474 error_code = 6;
475 error_subcode = 0;
476 assert_eq!(
477 parse_error_codes(&error_code, &error_subcode),
478 Ok(BgpError::BgpCeaseNotification(
479 BgpCeaseNotificationMessageSubcode::RESERVED
480 ))
481 );
482 error_subcode = 1;
483 assert_eq!(
484 parse_error_codes(&error_code, &error_subcode),
485 Ok(BgpError::BgpCeaseNotification(
486 BgpCeaseNotificationMessageSubcode::MAXIMUM_NUMBER_OF_PREFIXES_REACHED
487 ))
488 );
489 error_subcode = 2;
490 assert_eq!(
491 parse_error_codes(&error_code, &error_subcode),
492 Ok(BgpError::BgpCeaseNotification(
493 BgpCeaseNotificationMessageSubcode::ADMINISTRATIVE_SHUTDOWN
494 ))
495 );
496 error_subcode = 3;
497 assert_eq!(
498 parse_error_codes(&error_code, &error_subcode),
499 Ok(BgpError::BgpCeaseNotification(
500 BgpCeaseNotificationMessageSubcode::PEER_DE_CONFIGURED
501 ))
502 );
503 error_subcode = 4;
504 assert_eq!(
505 parse_error_codes(&error_code, &error_subcode),
506 Ok(BgpError::BgpCeaseNotification(
507 BgpCeaseNotificationMessageSubcode::ADMINISTRATIVE_RESET
508 ))
509 );
510 error_subcode = 5;
511 assert_eq!(
512 parse_error_codes(&error_code, &error_subcode),
513 Ok(BgpError::BgpCeaseNotification(
514 BgpCeaseNotificationMessageSubcode::CONNECTION_REJECTED
515 ))
516 );
517 error_subcode = 6;
518 assert_eq!(
519 parse_error_codes(&error_code, &error_subcode),
520 Ok(BgpError::BgpCeaseNotification(
521 BgpCeaseNotificationMessageSubcode::OTHER_CONFIGURATION_CHANGE
522 ))
523 );
524 error_subcode = 7;
525 assert_eq!(
526 parse_error_codes(&error_code, &error_subcode),
527 Ok(BgpError::BgpCeaseNotification(
528 BgpCeaseNotificationMessageSubcode::CONNECTION_COLLISION_RESOLUTION
529 ))
530 );
531 error_subcode = 8;
532 assert_eq!(
533 parse_error_codes(&error_code, &error_subcode),
534 Ok(BgpError::BgpCeaseNotification(
535 BgpCeaseNotificationMessageSubcode::OUT_OF_RESOURCES
536 ))
537 );
538 error_subcode = 9;
539 assert_eq!(
540 parse_error_codes(&error_code, &error_subcode),
541 Ok(BgpError::BgpCeaseNotification(
542 BgpCeaseNotificationMessageSubcode::HARD_RESET
543 ))
544 );
545 error_subcode = 10;
546 assert_eq!(
547 parse_error_codes(&error_code, &error_subcode),
548 Ok(BgpError::BgpCeaseNotification(
549 BgpCeaseNotificationMessageSubcode::BFD_DOWN
550 ))
551 );
552 error_subcode = 11;
553 assert_eq!(
554 parse_error_codes(&error_code, &error_subcode),
555 Err(BgpErrorCodeParsingError::UnknownSubcode(11))
556 );
557
558 error_code = 7;
559 error_subcode = 0;
560 assert_eq!(
561 parse_error_codes(&error_code, &error_subcode),
562 Ok(BgpError::BgpRouteFreshMessageError(
563 BgpRouteRefreshMessageErrorSubcode::RESERVED
564 ))
565 );
566 error_subcode = 1;
567 assert_eq!(
568 parse_error_codes(&error_code, &error_subcode),
569 Ok(BgpError::BgpRouteFreshMessageError(
570 BgpRouteRefreshMessageErrorSubcode::INVALID_MESSAGE_LENGTH
571 ))
572 );
573 error_subcode = 2;
574 assert_eq!(
575 parse_error_codes(&error_code, &error_subcode),
576 Err(BgpErrorCodeParsingError::UnknownSubcode(2))
577 );
578
579 error_code = 8;
580 assert_eq!(
581 parse_error_codes(&error_code, &error_subcode),
582 Err(BgpErrorCodeParsingError::UnknownCode(8))
583 );
584 }
585}