1use crate::network::Asn;
2use enum_primitive_derive::Primitive;
3use serde::Serialize;
4use std::fmt::Formatter;
5use std::net::{Ipv4Addr, Ipv6Addr};
6
7#[derive(Debug, PartialEq, Copy, Clone, Eq)]
8pub enum MetaCommunity {
9 Community(Community),
10 ExtendedCommunity(ExtendedCommunity),
11 LargeCommunity(LargeCommunity),
12}
13
14#[derive(Debug, PartialEq, Copy, Clone, Eq)]
15pub enum Community {
16 NoExport,
17 NoAdvertise,
18 NoExportSubConfed,
19 Custom(Asn, u16),
20}
21
22#[derive(Debug, PartialEq, Clone, Copy, Eq)]
29pub struct LargeCommunity {
30 pub global_administrator: u32,
31 pub local_data: [u32; 2],
32}
33
34impl LargeCommunity {
35 pub fn new(global_administrator: u32, local_data: [u32; 2]) -> LargeCommunity {
36 LargeCommunity {
37 global_administrator,
38 local_data,
39 }
40 }
41}
42
43#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone)]
45pub enum ExtendedCommunityType {
46 TransitiveTwoOctetAsSpecific = 0x00,
48 TransitiveIpv4AddressSpecific = 0x01,
49 TransitiveFourOctetAsSpecific = 0x02,
50 TransitiveOpaque = 0x03,
51
52 NonTransitiveTwoOctetAsSpecific = 0x40,
54 NonTransitiveIpv4AddressSpecific = 0x41,
55 NonTransitiveFourOctetAsSpecific = 0x42,
56 NonTransitiveOpaque = 0x43,
57 }
59
60#[derive(Debug, PartialEq, Clone, Copy, Eq)]
98pub enum ExtendedCommunity {
99 TransitiveTwoOctetAsSpecific(TwoOctetAsSpecific),
100 TransitiveIpv4AddressSpecific(Ipv4AddressSpecific),
101 TransitiveFourOctetAsSpecific(FourOctetAsSpecific),
102 TransitiveOpaque(Opaque),
103 NonTransitiveTwoOctetAsSpecific(TwoOctetAsSpecific),
104 NonTransitiveIpv4AddressSpecific(Ipv4AddressSpecific),
105 NonTransitiveFourOctetAsSpecific(FourOctetAsSpecific),
106 NonTransitiveOpaque(Opaque),
107 Ipv6AddressSpecific(Ipv6AddressSpecific),
108 Raw([u8; 8]),
109}
110
111#[derive(Debug, PartialEq, Clone, Copy, Eq)]
112pub struct Ipv6AddressSpecific {
113 pub ec_type: u8,
114 pub ec_subtype: u8,
115 pub global_administrator: Ipv6Addr,
117 pub local_administrator: [u8; 2],
119}
120
121#[derive(Debug, PartialEq, Clone, Copy, Eq)]
125pub struct TwoOctetAsSpecific {
126 pub ec_type: u8,
127 pub ec_subtype: u8,
128 pub global_administrator: Asn,
130 pub local_administrator: [u8; 4],
132}
133
134#[derive(Debug, PartialEq, Clone, Copy, Eq)]
138pub struct FourOctetAsSpecific {
139 pub ec_type: u8,
140 pub ec_subtype: u8,
141 pub global_administrator: Asn,
143 pub local_administrator: [u8; 2],
145}
146
147#[derive(Debug, PartialEq, Clone, Copy, Eq)]
151pub struct Ipv4AddressSpecific {
152 pub ec_type: u8,
153 pub ec_subtype: u8,
154 pub global_administrator: Ipv4Addr,
156 pub local_administrator: [u8; 2],
158}
159
160#[derive(Debug, PartialEq, Clone, Copy, Eq)]
164pub struct Opaque {
165 pub ec_type: u8,
166 pub ec_subtype: u8,
167 pub value: [u8; 6],
169}
170
171fn bytes_to_string(bytes: &[u8]) -> String {
176 bytes
177 .iter()
178 .map(|x| format!("{:02X}", x))
179 .collect::<Vec<String>>()
180 .join("")
181}
182
183impl std::fmt::Display for Community {
184 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
185 write!(
186 f,
187 "{}",
188 match self {
189 Community::NoExport => {
190 "no-export".to_string()
191 }
192 Community::NoAdvertise => {
193 "no-advertise".to_string()
194 }
195 Community::NoExportSubConfed => {
196 "no-export-sub-confed".to_string()
197 }
198 Community::Custom(asn, value) => {
199 format!("{}:{}", asn, value)
200 }
201 }
202 )
203 }
204}
205
206impl std::fmt::Display for LargeCommunity {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 write!(
209 f,
210 "lg:{}:{}:{}",
211 self.global_administrator, self.local_data[0], self.local_data[1]
212 )
213 }
214}
215
216impl std::fmt::Display for ExtendedCommunity {
217 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218 write!(
219 f,
220 "{}",
221 match self {
222 ExtendedCommunity::TransitiveTwoOctetAsSpecific(ec)
223 | ExtendedCommunity::NonTransitiveTwoOctetAsSpecific(ec) => {
224 format!(
225 "ecas2:{}:{}:{}:{}",
226 ec.ec_type,
227 ec.ec_subtype,
228 ec.global_administrator,
229 bytes_to_string(&ec.local_administrator)
230 )
231 }
232 ExtendedCommunity::TransitiveIpv4AddressSpecific(ec)
233 | ExtendedCommunity::NonTransitiveIpv4AddressSpecific(ec) => {
234 format!(
235 "ecv4:{}:{}:{}:{}",
236 ec.ec_type,
237 ec.ec_subtype,
238 ec.global_administrator,
239 bytes_to_string(&ec.local_administrator)
240 )
241 }
242 ExtendedCommunity::TransitiveFourOctetAsSpecific(ec)
243 | ExtendedCommunity::NonTransitiveFourOctetAsSpecific(ec) => {
244 format!(
245 "ecas4:{}:{}:{}:{}",
246 ec.ec_type,
247 ec.ec_subtype,
248 ec.global_administrator,
249 bytes_to_string(&ec.local_administrator)
250 )
251 }
252 ExtendedCommunity::TransitiveOpaque(ec)
253 | ExtendedCommunity::NonTransitiveOpaque(ec) => {
254 format!(
255 "ecop:{}:{}:{}",
256 ec.ec_type,
257 ec.ec_subtype,
258 bytes_to_string(&ec.value)
259 )
260 }
261 ExtendedCommunity::Ipv6AddressSpecific(ec) => {
262 format!(
263 "ecv6:{}:{}:{}:{}",
264 ec.ec_type,
265 ec.ec_subtype,
266 ec.global_administrator,
267 bytes_to_string(&ec.local_administrator)
268 )
269 }
270 ExtendedCommunity::Raw(ec) => {
271 format!("ecraw:{}", bytes_to_string(ec))
272 }
273 }
274 )
275 }
276}
277
278impl std::fmt::Display for MetaCommunity {
279 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
280 write!(
281 f,
282 "{}",
283 match self {
284 MetaCommunity::Community(c) => {
285 c.to_string()
286 }
287 MetaCommunity::ExtendedCommunity(c) => {
288 c.to_string()
289 }
290 MetaCommunity::LargeCommunity(c) => {
291 c.to_string()
292 }
293 }
294 )
295 }
296}
297
298macro_rules! impl_serialize {
303 ($a:ident) => {
304 impl Serialize for $a {
305 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
306 where
307 S: serde::Serializer,
308 {
309 serializer.serialize_str(self.to_string().as_str())
310 }
311 }
312 };
313}
314
315impl_serialize!(Community);
316impl_serialize!(ExtendedCommunity);
317impl_serialize!(LargeCommunity);
318impl_serialize!(MetaCommunity);