1use crate::bgp::{Community, ExtendedCommunity, LargeCommunity};
3use crate::network::*;
4use itertools::Itertools;
5use serde::{Serialize, Serializer};
6use std::fmt::{Display, Formatter};
7use std::net::IpAddr;
8
9pub enum AttributeFlagsBit {
32 OptionalBit = 0b10000000,
34 TransitiveBit = 0b01000000,
36 PartialBit = 0b00100000,
38 ExtendedLengthBit = 0b00010000,
40}
41
42#[allow(non_camel_case_types)]
48#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone, Serialize)]
49pub enum AttrType {
50 RESERVED = 0,
51 ORIGIN = 1,
52 AS_PATH = 2,
53 NEXT_HOP = 3,
54 MULTI_EXIT_DISCRIMINATOR = 4,
55 LOCAL_PREFERENCE = 5,
56 ATOMIC_AGGREGATE = 6,
57 AGGREGATOR = 7,
58 COMMUNITIES = 8,
59 ORIGINATOR_ID = 9,
61 CLUSTER_LIST = 10,
62 CLUSTER_ID = 13,
64 MP_REACHABLE_NLRI = 14,
65 MP_UNREACHABLE_NLRI = 15,
66 EXTENDED_COMMUNITIES = 16,
68 AS4_PATH = 17,
69 AS4_AGGREGATOR = 18,
70 PMSI_TUNNEL = 22,
71 TUNNEL_ENCAPSULATION = 23,
72 TRAFFIC_ENGINEERING = 24,
73 IPV6_ADDRESS_SPECIFIC_EXTENDED_COMMUNITIES = 25,
74 AIGP = 26,
75 PE_DISTINGUISHER_LABELS = 27,
76 BGP_LS_ATTRIBUTE = 29,
77 LARGE_COMMUNITIES = 32,
78 BGPSEC_PATH = 33,
79 ONLY_TO_CUSTOMER = 35,
80 SFP_ATTRIBUTE = 37,
81 BFD_DISCRIMINATOR = 38,
82 BGP_PREFIX_SID = 40,
83 ATTR_SET = 128,
84 DEVELOPMENT = 255,
86}
87
88pub fn get_deprecated_attr_type(attr_type: u8) -> Option<&'static str> {
89 match attr_type {
90 11 => Some("DPA"),
91 12 => Some("ADVERTISER"),
92 13 => Some("RCID_PATH"),
93 19 => Some("SAFI Specific Attribute"),
94 20 => Some("Connector Attribute"),
95 21 => Some("AS_PATHLIMIT"),
96 28 => Some("BGP Entropy Label Capability"),
97 30 | 31 | 129 | 241 | 242 | 243 => Some("RFC8093"),
98
99 _ => None,
100 }
101}
102
103#[allow(non_camel_case_types)]
104#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone)]
105pub enum Origin {
106 IGP = 0,
107 EGP = 1,
108 INCOMPLETE = 2,
109}
110
111#[allow(non_camel_case_types)]
112#[derive(Debug, Primitive, PartialEq, Eq, Hash, Copy, Clone)]
113pub enum AtomicAggregate {
114 NAG = 0,
115 AG = 1,
116}
117
118#[derive(Debug, PartialEq, Clone, Serialize, Eq)]
120pub struct Attribute {
121 pub attr_type: AttrType,
122 pub value: AttributeValue,
123 pub flag: u8,
124}
125
126#[derive(Debug, PartialEq, Clone, Serialize, Eq)]
128pub enum AttributeValue {
129 Origin(Origin),
130 AsPath(AsPath),
131 As4Path(AsPath),
132 NextHop(IpAddr),
133 MultiExitDiscriminator(u32),
134 LocalPreference(u32),
135 OnlyToCustomer(u32),
136 AtomicAggregate(AtomicAggregate),
137 Aggregator(Asn, IpAddr),
138 Communities(Vec<Community>),
139 ExtendedCommunities(Vec<ExtendedCommunity>),
140 LargeCommunities(Vec<LargeCommunity>),
141 OriginatorId(IpAddr),
142 Clusters(Vec<IpAddr>),
143 MpReachNlri(Nlri),
144 MpUnreachNlri(Nlri),
145 Development(Vec<u8>),
146}
147
148#[derive(Debug, PartialEq, Clone, Eq)]
154pub enum AsPathSegment {
155 AsSequence(Vec<Asn>),
156 AsSet(Vec<Asn>),
157 ConfedSequence(Vec<Asn>),
158 ConfedSet(Vec<Asn>),
159}
160
161impl AsPathSegment {
162 pub fn count_asns(&self) -> usize {
163 match self {
164 AsPathSegment::AsSequence(v) => v.len(),
165 AsPathSegment::AsSet(_) => 1,
166 AsPathSegment::ConfedSequence(_) | AsPathSegment::ConfedSet(_) => 0,
167 }
168 }
169}
170
171#[derive(Debug, PartialEq, Clone, Eq)]
172pub struct AsPath {
173 pub segments: Vec<AsPathSegment>,
174}
175
176impl Default for AsPath {
177 fn default() -> Self {
178 Self::new()
179 }
180}
181
182impl AsPath {
183 pub fn new() -> AsPath {
184 AsPath { segments: vec![] }
185 }
186
187 pub fn from_segments(segments: Vec<AsPathSegment>) -> AsPath {
188 AsPath { segments }
189 }
190
191 pub fn add_segment(&mut self, segment: AsPathSegment) {
192 self.segments.push(segment);
193 }
194
195 pub fn segments(&self) -> &Vec<AsPathSegment> {
196 &self.segments
197 }
198
199 pub fn count_asns(&self) -> usize {
200 self.segments.iter().map(AsPathSegment::count_asns).sum()
201 }
202
203 pub fn merge_aspath_as4path(aspath: &AsPath, as4path: &AsPath) -> Option<AsPath> {
222 if aspath.count_asns() < as4path.count_asns() {
223 return Some(aspath.clone());
224 }
225
226 let mut as4iter = as4path.segments.iter();
227 let mut as4seg = as4iter.next();
228 let mut new_segs: Vec<AsPathSegment> = vec![];
229 if as4seg.is_none() {
230 new_segs.extend(aspath.segments.clone());
231 return Some(AsPath { segments: new_segs });
232 }
233
234 for seg in &aspath.segments {
235 let as4seg_unwrapped = as4seg.unwrap();
236 if let (AsPathSegment::AsSequence(seq), AsPathSegment::AsSequence(seq4)) =
237 (seg, as4seg_unwrapped)
238 {
239 let diff_len = seq.len() - seq4.len();
240 let mut new_seq: Vec<Asn> = vec![];
241 new_seq.extend(seq.iter().take(diff_len));
242 new_seq.extend(seq4);
243 new_segs.push(AsPathSegment::AsSequence(new_seq));
244 } else {
245 new_segs.push(as4seg_unwrapped.clone());
246 }
247 as4seg = as4iter.next();
248 }
249
250 Some(AsPath { segments: new_segs })
251 }
252
253 pub fn get_origin(&self) -> Option<Vec<Asn>> {
254 if let Some(seg) = self.segments.last() {
255 match seg {
256 AsPathSegment::AsSequence(v) => v.last().map(|n| vec![*n]),
257 AsPathSegment::AsSet(v) => Some(v.clone()),
258 AsPathSegment::ConfedSequence(_) | AsPathSegment::ConfedSet(_) => None,
259 }
260 } else {
261 None
262 }
263 }
264
265 pub fn to_u32_vec(&self) -> Option<Vec<u32>> {
266 if !self
267 .segments
268 .iter()
269 .all(|seg| matches!(seg, AsPathSegment::AsSequence(_v)))
270 {
271 return None;
273 }
274 let mut path = vec![];
275 for s in &self.segments {
276 if let AsPathSegment::AsSequence(seg) = s {
277 for asn in seg {
278 path.push(asn.asn);
279 }
280 } else {
281 return None;
283 }
284 }
285 Some(path)
286 }
287}
288
289#[derive(Debug, PartialEq, Clone, Serialize, Eq)]
294pub struct Nlri {
295 pub afi: Afi,
296 pub safi: Safi,
297 pub next_hop: Option<NextHopAddress>,
298 pub prefixes: Vec<NetworkPrefix>,
299}
300
301#[derive(Debug, PartialEq, Clone, Serialize)]
302pub struct MpReachableNlri {
303 afi: Afi,
304 safi: Safi,
305 next_hop: NextHopAddress,
306 prefixes: Vec<NetworkPrefix>,
307}
308
309impl MpReachableNlri {
310 pub fn new(
311 afi: Afi,
312 safi: Safi,
313 next_hop: NextHopAddress,
314 prefixes: Vec<NetworkPrefix>,
315 ) -> MpReachableNlri {
316 MpReachableNlri {
317 afi,
318 safi,
319 next_hop,
320 prefixes,
321 }
322 }
323}
324
325#[derive(Debug, PartialEq, Copy, Clone)]
326pub struct MpReachableNlriV2 {
327 next_hop: NextHopAddress,
328}
329
330#[derive(Debug, PartialEq, Clone)]
331pub struct MpUnreachableNlri {
332 afi: Afi,
333 safi: Safi,
334 prefixes: Vec<NetworkPrefix>,
335}
336
337impl MpUnreachableNlri {
338 pub fn new(afi: Afi, safi: Safi, prefixes: Vec<NetworkPrefix>) -> MpUnreachableNlri {
339 MpUnreachableNlri {
340 afi,
341 safi,
342 prefixes,
343 }
344 }
345}
346
347impl Display for Origin {
352 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
353 let s = match self {
354 Origin::IGP => "IGP",
355 Origin::EGP => "EGP",
356 Origin::INCOMPLETE => "INCOMPLETE",
357 };
358 write!(f, "{}", s)
359 }
360}
361
362impl Display for AtomicAggregate {
363 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
364 write!(
365 f,
366 "{}",
367 match self {
368 AtomicAggregate::NAG => {
369 "NAG"
370 }
371 AtomicAggregate::AG => {
372 "AG"
373 }
374 }
375 )
376 }
377}
378
379impl Display for NextHopAddress {
380 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
381 write!(
382 f,
383 "{}",
384 match self {
385 NextHopAddress::Ipv4(v) => {
386 v.to_string()
387 }
388 NextHopAddress::Ipv6(v) => {
389 v.to_string()
390 }
391 NextHopAddress::Ipv6LinkLocal(v1, _v2) => {
392 v1.to_string()
393 }
394 }
395 )
396 }
397}
398
399impl Display for AsPath {
400 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
401 write!(
402 f,
403 "{}",
404 self.segments()
405 .iter()
406 .map(|seg| match seg {
407 AsPathSegment::AsSequence(v) | AsPathSegment::ConfedSequence(v) =>
408 v.iter().join(" "),
409 AsPathSegment::AsSet(v) | AsPathSegment::ConfedSet(v) => {
410 format!("{{{}}}", v.iter().join(","))
411 }
412 })
413 .join(" ")
414 )
415 }
416}
417
418impl Serialize for AsPath {
423 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
424 where
425 S: Serializer,
426 {
427 serializer.serialize_str(self.to_string().as_str())
428 }
429}
430
431impl Serialize for Origin {
432 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
433 where
434 S: Serializer,
435 {
436 serializer.serialize_str(self.to_string().as_str())
437 }
438}
439
440impl Serialize for AtomicAggregate {
441 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
442 where
443 S: Serializer,
444 {
445 serializer.serialize_str(self.to_string().as_str())
446 }
447}
448
449#[cfg(test)]
450mod tests {
451 use crate::bgp::attributes::{AsPath, AsPathSegment};
452
453 #[test]
454 fn test_aspath_as4path_merge() {
455 let aspath = AsPath {
456 segments: vec![AsPathSegment::AsSequence(
457 [1, 2, 3, 5].map(|i| i.into()).to_vec(),
458 )],
459 };
460 let as4path = AsPath {
461 segments: vec![AsPathSegment::AsSequence(
462 [2, 3, 7].map(|i| i.into()).to_vec(),
463 )],
464 };
465 let newpath = AsPath::merge_aspath_as4path(&aspath, &as4path).unwrap();
466 assert_eq!(
467 newpath.segments[0],
468 AsPathSegment::AsSequence([1, 2, 3, 7].map(|i| { i.into() }).to_vec())
469 );
470 }
471
472 #[test]
473 fn test_get_origin() {
474 let aspath = AsPath {
475 segments: vec![AsPathSegment::AsSequence(
476 [1, 2, 3, 5].map(|i| i.into()).to_vec(),
477 )],
478 };
479 let origins = aspath.get_origin();
480 assert!(origins.is_some());
481 assert_eq!(origins.unwrap(), vec![5]);
482
483 let aspath = AsPath {
484 segments: vec![
485 AsPathSegment::AsSequence([1, 2, 3, 5].map(|i| i.into()).to_vec()),
486 AsPathSegment::AsSet([7, 8].map(|i| i.into()).to_vec()),
487 ],
488 };
489 let origins = aspath.get_origin();
490 assert!(origins.is_some());
491 assert_eq!(origins.unwrap(), vec![7, 8]);
492 }
493
494 #[test]
495 fn test_aspath_to_vec() {
496 let as4path = AsPath {
497 segments: vec![AsPathSegment::AsSequence(
498 [2, 3, 4].map(|i| i.into()).to_vec(),
499 )],
500 };
501 assert_eq!(as4path.to_u32_vec(), Some(vec![2, 3, 4]));
502
503 let as4path = AsPath {
504 segments: vec![
505 AsPathSegment::AsSequence([2, 3, 4].map(|i| i.into()).to_vec()),
506 AsPathSegment::AsSequence([5, 6, 7].map(|i| i.into()).to_vec()),
507 ],
508 };
509 assert_eq!(as4path.to_u32_vec(), Some(vec![2, 3, 4, 5, 6, 7]));
510
511 let as4path = AsPath {
512 segments: vec![AsPathSegment::AsSet([2, 3, 4].map(|i| i.into()).to_vec())],
513 };
514 assert_eq!(as4path.to_u32_vec(), None);
515 }
516}