Skip to main content

bgp_models/bgp/
capabilities.rs

1use num_traits::FromPrimitive;
2use serde::Serialize;
3use std::error::Error;
4use std::fmt::{Display, Formatter};
5
6/// BGP capability parsing error
7#[derive(Debug, PartialEq, Eq, Clone, Serialize)]
8pub enum BgpCapabilityParsingError {
9    Unassigned(u8),
10    DeprecatedCode(u8),
11    ReservedCode(u8),
12    ReservedExperimentalCode(u8),
13}
14
15impl Display for BgpCapabilityParsingError {
16    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
17        match self {
18            BgpCapabilityParsingError::Unassigned(v) => {
19                write!(f, "unassigned BGP capability code: {}", v)
20            }
21            BgpCapabilityParsingError::DeprecatedCode(v) => {
22                write!(f, "deprecated BGP capability code: {}", v)
23            }
24            BgpCapabilityParsingError::ReservedCode(v) => {
25                write!(f, "reserved BGP capability code: {}", v)
26            }
27            BgpCapabilityParsingError::ReservedExperimentalCode(v) => {
28                write!(
29                    f,
30                    "reserved BGP capability code for experimental use: {}",
31                    v
32                )
33            }
34        }
35    }
36}
37
38impl Error for BgpCapabilityParsingError {}
39
40#[allow(non_camel_case_types)]
41#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
42pub enum BgpCapabilityType {
43    MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4 = 1,
44    ROUTE_REFRESH_CAPABILITY_FOR_BGP_4 = 2,
45    OUTBOUND_ROUTE_FILTERING_CAPABILITY = 3,
46    EXTENDED_NEXT_HOP_ENCODING = 5,
47    BGP_EXTENDED_MESSAGE = 6,
48    BGPSEC_CAPABILITY = 7,
49    MULTIPLE_LABELS_CAPABILITY = 8,
50    BGP_ROLE = 9,
51    GRACEFUL_RESTART_CAPABILITY = 64,
52    SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY = 65,
53    SUPPORT_FOR_DYNAMIC_CAPABILITY = 67,
54    MULTISESSION_BGP_CAPABILITY = 68,
55    ADD_PATH_CAPABILITY = 69,
56    ENHANCED_ROUTE_REFRESH_CAPABILITY = 70,
57    LONG_LIVED_GRACEFUL_RESTART_CAPABILITY = 71,
58    ROUTING_POLICY_DISTRIBUTION = 72,
59    FQDN_CAPABILITY = 73,
60}
61
62pub fn parse_capability(
63    capability_code: &u8,
64) -> Result<BgpCapabilityType, BgpCapabilityParsingError> {
65    match BgpCapabilityType::from_u8(*capability_code) {
66        Some(v) => Ok(v),
67        None => {
68            if [4, 66, 128, 129, 130, 131, 184, 185].contains(capability_code) {
69                Err(BgpCapabilityParsingError::DeprecatedCode(*capability_code))
70            } else if *capability_code == 0 || *capability_code == 255 {
71                Err(BgpCapabilityParsingError::ReservedCode(*capability_code))
72            } else if *capability_code >= 239 && *capability_code <= 254 {
73                Err(BgpCapabilityParsingError::ReservedExperimentalCode(
74                    *capability_code,
75                ))
76            } else {
77                Err(BgpCapabilityParsingError::Unassigned(*capability_code))
78            }
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_parsing_capability() {
89        let mut code;
90
91        // reserved
92        code = 0;
93        assert_eq!(
94            parse_capability(&code),
95            Err(BgpCapabilityParsingError::ReservedCode(code))
96        );
97        code = 255;
98        assert_eq!(
99            parse_capability(&code),
100            Err(BgpCapabilityParsingError::ReservedCode(code))
101        );
102
103        // deprecated
104        for code in [4, 66, 128, 129, 130, 131, 184, 185] {
105            assert_eq!(
106                parse_capability(&code),
107                Err(BgpCapabilityParsingError::DeprecatedCode(code))
108            );
109        }
110
111        // unassigned
112        for code in 10..=63 {
113            assert_eq!(
114                parse_capability(&code),
115                Err(BgpCapabilityParsingError::Unassigned(code))
116            );
117        }
118        for code in 74..=127 {
119            assert_eq!(
120                parse_capability(&code),
121                Err(BgpCapabilityParsingError::Unassigned(code))
122            );
123        }
124        for code in 132..=183 {
125            assert_eq!(
126                parse_capability(&code),
127                Err(BgpCapabilityParsingError::Unassigned(code))
128            );
129        }
130        for code in 186..=238 {
131            assert_eq!(
132                parse_capability(&code),
133                Err(BgpCapabilityParsingError::Unassigned(code))
134            );
135        }
136
137        // valid capabilities
138        code = 1;
139        assert_eq!(
140            parse_capability(&code),
141            Ok(BgpCapabilityType::MULTIPROTOCOL_EXTENSIONS_FOR_BGP_4)
142        );
143        code = 2;
144        assert_eq!(
145            parse_capability(&code),
146            Ok(BgpCapabilityType::ROUTE_REFRESH_CAPABILITY_FOR_BGP_4)
147        );
148        code = 3;
149        assert_eq!(
150            parse_capability(&code),
151            Ok(BgpCapabilityType::OUTBOUND_ROUTE_FILTERING_CAPABILITY)
152        );
153        code = 5;
154        assert_eq!(
155            parse_capability(&code),
156            Ok(BgpCapabilityType::EXTENDED_NEXT_HOP_ENCODING)
157        );
158        code = 6;
159        assert_eq!(
160            parse_capability(&code),
161            Ok(BgpCapabilityType::BGP_EXTENDED_MESSAGE)
162        );
163        code = 7;
164        assert_eq!(
165            parse_capability(&code),
166            Ok(BgpCapabilityType::BGPSEC_CAPABILITY)
167        );
168        code = 8;
169        assert_eq!(
170            parse_capability(&code),
171            Ok(BgpCapabilityType::MULTIPLE_LABELS_CAPABILITY)
172        );
173        code = 9;
174        assert_eq!(parse_capability(&code), Ok(BgpCapabilityType::BGP_ROLE));
175
176        code = 64;
177        assert_eq!(
178            parse_capability(&code),
179            Ok(BgpCapabilityType::GRACEFUL_RESTART_CAPABILITY)
180        );
181        code = 65;
182        assert_eq!(
183            parse_capability(&code),
184            Ok(BgpCapabilityType::SUPPORT_FOR_4_OCTET_AS_NUMBER_CAPABILITY)
185        );
186        code = 67;
187        assert_eq!(
188            parse_capability(&code),
189            Ok(BgpCapabilityType::SUPPORT_FOR_DYNAMIC_CAPABILITY)
190        );
191        code = 68;
192        assert_eq!(
193            parse_capability(&code),
194            Ok(BgpCapabilityType::MULTISESSION_BGP_CAPABILITY)
195        );
196        code = 69;
197        assert_eq!(
198            parse_capability(&code),
199            Ok(BgpCapabilityType::ADD_PATH_CAPABILITY)
200        );
201        code = 70;
202        assert_eq!(
203            parse_capability(&code),
204            Ok(BgpCapabilityType::ENHANCED_ROUTE_REFRESH_CAPABILITY)
205        );
206        code = 71;
207        assert_eq!(
208            parse_capability(&code),
209            Ok(BgpCapabilityType::LONG_LIVED_GRACEFUL_RESTART_CAPABILITY)
210        );
211        code = 72;
212        assert_eq!(
213            parse_capability(&code),
214            Ok(BgpCapabilityType::ROUTING_POLICY_DISTRIBUTION)
215        );
216        code = 73;
217        assert_eq!(
218            parse_capability(&code),
219            Ok(BgpCapabilityType::FQDN_CAPABILITY)
220        );
221    }
222}