bgp_models/bgp/
error.rs

1//! BGP error code module that maintains explicit error codes assigned by IANA.
2//!
3//! The full list of IANA error code assignments for BGP can be viewed at here:
4//! <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-3>.
5use num_traits::FromPrimitive;
6use serde::Serialize;
7use std::error::Error;
8use std::fmt::{Display, Formatter};
9
10/// Error for parsing BGP error code
11#[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
40/// Utility function to parse a pair of BGP error code and subcode (both u8) into a defined struct.
41pub 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/// BGP Error Subcode enum.
87///
88/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-4>
89#[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/// Message Header Error subcodes
103///
104/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-5>
105///
106/// *See source code for number assignment*
107#[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    // 4 - 255: unassigned
115}
116
117/// OPEN Message Error subcodes
118///
119/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-6>
120///
121/// *See source code for number assignment*
122#[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    // 5 -- deprecated
131    UNACCEPTABLE_HOLD_TIME = 6,
132    UNSUPPORTED_CAPACITY = 7,
133    // 8 -- deprecated
134    // 9 -- deprecated
135    // 10 -- deprecated
136    ROLE_MISMATCH = 11,
137    // 12 - 255: unassinged
138}
139
140/// UPDATE Message Error subcodes
141///
142/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-finite-state-machine-error-subcodes>
143///
144/// *See source code for number assignment*
145#[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    // 7 - deprecated
156    INVALID_NEXT_HOP_ATTRIBUTE = 8,
157    OPTIONAL_ATTRIBUTE_ERROR = 9,
158    INVALID_NETWORK_FIELD = 10,
159    MALFORMED_AS_PATH = 11,
160    // 12 - 255: unassigned
161}
162
163/// BGP Finite State Machine Error Subcodes
164///
165/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-finite-state-machine-error-subcodes>
166///
167/// *See source code for number assignment*
168#[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    // 4 - 255: unassigned
176}
177
178/// BGP Cease NOTIFICATION message subcodes
179///
180/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#bgp-parameters-8>
181///
182/// *See source code for number assignment*
183#[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, // TEMPORARY - registered 2022-02-23, expires 2023-02-23
197                   // 11 - 255: unassigned
198}
199
200/// BGP ROUTE-REFRESH Message Error subcodes
201///
202/// <https://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#route-refresh-error-subcodes>
203///
204/// *See source code for number assignment*
205#[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    // 2 - 255: unassigned
211}
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        // deprecated subcodes
321        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        // deprecated subcodes
413        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        // subcode should not matter here
433        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}