From a4f1282978a61edda8bd0b197cb02c2d7192823d Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Thu, 21 Nov 2024 20:03:59 -0800 Subject: [PATCH 1/3] support converting singleton AsSet to Vec --- src/models/bgp/attributes/aspath.rs | 65 +++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/src/models/bgp/attributes/aspath.rs b/src/models/bgp/attributes/aspath.rs index 7b2db45..b323870 100644 --- a/src/models/bgp/attributes/aspath.rs +++ b/src/models/bgp/attributes/aspath.rs @@ -145,6 +145,15 @@ impl AsPathSegment { } Some(p) } + AsPathSegment::AsSet(v) => { + if v.len() == 1 { + // if the segment is an AS_SET and the length is 1, we can consider this a + // single ASN path vector + Some(vec![v[0].into()]) + } else { + None + } + } _ => None, } } @@ -689,9 +698,32 @@ impl AsPath { } pub fn to_u32_vec_opt(&self, dedup: bool) -> Option> { - match self.segments.last() { - None => None, - Some(v) => v.to_u32_vec_opt(dedup), + let mut path = vec![]; + + // Iterate over the segments in reverse order + for seg in self.segments.iter().rev() { + if let Some(p) = seg.to_u32_vec_opt(dedup) { + // for each segment, we also reverse the order of ASNs so that we will eventually + // get a reversed AS path stored in `path`. + path.extend(p.iter().rev()); + } else { + // If we encounter a segment that cannot be converted to a u32, we return None. + // This is because the path is not a simple sequence of ASNs, and returning partial + // AS path would be misleading. + return None; + } + } + + match path.is_empty() { + true => { + // empty path is not a valid AS path + None + } + false => { + // reverse the order of ASNs to get the original path + path.reverse(); + Some(path) + } } } } @@ -1212,14 +1244,39 @@ mod tests { } #[test] - fn test_segment_to_u32() { + fn test_path_to_u32() { + // regular sequence let path_segment = AsPathSegment::sequence([1, 2, 3, 3]); assert_eq!(path_segment.to_u32_vec_opt(false), Some(vec![1, 2, 3, 3])); assert_eq!(path_segment.to_u32_vec_opt(true), Some(vec![1, 2, 3])); + // regular set: should return None let path_segment = AsPathSegment::set([1, 2, 3, 3]); assert_eq!(path_segment.to_u32_vec_opt(false), None); assert_eq!(path_segment.to_u32_vec_opt(true), None); + + // singular set: should be converted to singleton vector + let path_segment = AsPathSegment::set([1]); + assert_eq!(path_segment.to_u32_vec_opt(false), Some(vec![1])); + assert_eq!(path_segment.to_u32_vec_opt(true), Some(vec![1])); + + // combination of a sequence and a few singleton sets, should be merged into a single vector + let as_path = AsPath::from_segments(vec![ + AsPathSegment::set([4]), + AsPathSegment::sequence([2, 3, 3]), + AsPathSegment::set([1]), + ]); + assert_eq!(as_path.to_u32_vec_opt(false), Some(vec![4, 2, 3, 3, 1])); + assert_eq!(as_path.to_u32_vec_opt(true), Some(vec![4, 2, 3, 1])); + + // should the path containing any non-convertable segments, return None + let as_path = AsPath::from_segments(vec![ + AsPathSegment::set([4, 2]), + AsPathSegment::sequence([2, 3, 3]), + AsPathSegment::set([1]), + ]); + assert_eq!(as_path.to_u32_vec_opt(false), None); + assert_eq!(as_path.to_u32_vec_opt(true), None); } #[test] From fb8cf933742095ffb28ed8fb8e66a67ea619e244 Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Thu, 21 Nov 2024 20:10:23 -0800 Subject: [PATCH 2/3] Update comments wording Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/models/bgp/attributes/aspath.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/bgp/attributes/aspath.rs b/src/models/bgp/attributes/aspath.rs index b323870..95b02e8 100644 --- a/src/models/bgp/attributes/aspath.rs +++ b/src/models/bgp/attributes/aspath.rs @@ -1269,7 +1269,7 @@ mod tests { assert_eq!(as_path.to_u32_vec_opt(false), Some(vec![4, 2, 3, 3, 1])); assert_eq!(as_path.to_u32_vec_opt(true), Some(vec![4, 2, 3, 1])); - // should the path containing any non-convertable segments, return None + // should the path containing any non-convertible segments, return None let as_path = AsPath::from_segments(vec![ AsPathSegment::set([4, 2]), AsPathSegment::sequence([2, 3, 3]), From 4a759e7d07c75ab3e657f88014bcaa65865d665f Mon Sep 17 00:00:00 2001 From: Mingwei Zhang Date: Thu, 21 Nov 2024 20:17:12 -0800 Subject: [PATCH 3/3] add tests for corner cases --- src/models/bgp/attributes/aspath.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/models/bgp/attributes/aspath.rs b/src/models/bgp/attributes/aspath.rs index 95b02e8..9d7166b 100644 --- a/src/models/bgp/attributes/aspath.rs +++ b/src/models/bgp/attributes/aspath.rs @@ -1277,6 +1277,21 @@ mod tests { ]); assert_eq!(as_path.to_u32_vec_opt(false), None); assert_eq!(as_path.to_u32_vec_opt(true), None); + + // other corner cases + + // empty path + let as_path = AsPath::from_segments(vec![]); + assert_eq!(as_path.to_u32_vec_opt(false), None); + assert_eq!(as_path.to_u32_vec_opt(true), None); + + // path with federation segments + let as_path = AsPath::from_segments(vec![ + AsPathSegment::ConfedSet(vec![Asn::new_32bit(1), Asn::new_32bit(2)]), + AsPathSegment::ConfedSequence(vec![Asn::new_32bit(3), Asn::new_32bit(4)]), + ]); + assert_eq!(as_path.to_u32_vec_opt(false), None); + assert_eq!(as_path.to_u32_vec_opt(true), None); } #[test]