Skip to content

Commit 76982a5

Browse files
committed
Store required attributes in attributes instead of vec
1 parent 8228248 commit 76982a5

File tree

5 files changed

+55
-19
lines changed

5 files changed

+55
-19
lines changed

src/models/bgp/attributes/mod.rs

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,8 @@ use bitflags::bitflags;
88
use itertools::chain;
99
use num_enum::{FromPrimitive, IntoPrimitive};
1010
use std::cmp::Ordering;
11-
use std::iter::{FromIterator, Map};
11+
use std::iter::FromIterator;
1212
use std::net::IpAddr;
13-
use std::slice::Iter;
14-
use std::vec::IntoIter;
1513

1614
use crate::error::BgpValidationWarning;
1715
use crate::models::*;
@@ -339,12 +337,41 @@ impl Attributes {
339337
}
340338
}
341339

340+
/// Count the total number of attributes (including well-known mandatory attributes)
341+
pub fn len(&self) -> usize {
342+
self.origin.iter().count() + self.as_path.iter().count() + self.next_hop.iter().count() + self.inner.len()
343+
}
344+
345+
/// Check if there are no attributes
346+
pub fn is_empty(&self) -> bool {
347+
self.len() == 0
348+
}
349+
350+
/// Get the first attribute if any exists
351+
pub fn first(&self) -> Option<&Attribute> {
352+
self.origin.as_ref()
353+
.or(self.as_path.as_ref())
354+
.or(self.next_hop.as_ref())
355+
.or(self.inner.first())
356+
}
357+
342358
/// Get an iterator over the held [AttributeValue]s. If you also need attribute flags, consider
343359
/// using [Attributes::into_attributes_iter] instead.
344360
pub fn iter(&self) -> <&'_ Self as IntoIterator>::IntoIter {
345361
self.into_iter()
346362
}
347363

364+
/// Get an iterator over references to the held [Attribute]s. If you do not need attribute flags,
365+
/// consider using [Attributes::iter] instead.
366+
pub fn attributes_iter(&self) -> impl Iterator<Item = &Attribute> {
367+
chain!(
368+
self.as_path.iter(),
369+
self.origin.iter(),
370+
self.next_hop.iter(),
371+
self.inner.iter(),
372+
)
373+
}
374+
348375
/// Get an iterator over the held [Attribute]s. If you do no not need attribute flags, consider
349376
/// using [Attributes::iter] instead.
350377
pub fn into_attributes_iter(self) -> impl Iterator<Item = Attribute> {
@@ -452,26 +479,35 @@ impl FromIterator<AttributeValue> for Attributes {
452479

453480
impl IntoIterator for Attributes {
454481
type Item = AttributeValue;
455-
type IntoIter = Map<IntoIter<Attribute>, fn(Attribute) -> AttributeValue>;
482+
type IntoIter = std::vec::IntoIter<AttributeValue>;
456483

457484
fn into_iter(self) -> Self::IntoIter {
458-
self.inner.into_iter().map(|x| x.value)
485+
chain!(
486+
self.as_path.into_iter(),
487+
self.origin.into_iter(),
488+
self.next_hop.into_iter(),
489+
self.inner.into_iter()
490+
)
491+
.map(|x| x.value)
492+
.collect::<Vec<_>>()
493+
.into_iter()
459494
}
460495
}
461496

462497
impl<'a> IntoIterator for &'a Attributes {
463498
type Item = &'a AttributeValue;
464-
type IntoIter = Map<Iter<'a, Attribute>, fn(&Attribute) -> &AttributeValue>;
499+
type IntoIter = std::vec::IntoIter<&'a AttributeValue>;
465500

466501
fn into_iter(self) -> Self::IntoIter {
467-
let tmp: Vec<_> = chain!(
502+
chain!(
468503
self.as_path.iter(),
469504
self.origin.iter(),
470505
self.next_hop.iter(),
471506
self.inner.iter()
472-
).collect();
473-
474-
tmp.as_slice().into_iter().map(|x| &x.value)
507+
)
508+
.map(|x| &x.value)
509+
.collect::<Vec<_>>()
510+
.into_iter()
475511
}
476512
}
477513

src/parser/bgp/attributes/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ impl Attribute {
459459
impl Attributes {
460460
pub fn encode(&self, asn_len: AsnLength) -> Bytes {
461461
let mut bytes = BytesMut::new();
462-
for attr in &self.iter() {
462+
for attr in self.attributes_iter() {
463463
bytes.extend(attr.encode(asn_len));
464464
}
465465
bytes.freeze()
@@ -481,9 +481,9 @@ mod tests {
481481
let attributes = parse_attributes(data, &asn_len, add_path, afi, safi, prefixes);
482482
assert!(attributes.is_ok());
483483
let attributes = attributes.unwrap();
484-
assert_eq!(attributes.inner.len(), 1);
484+
assert_eq!(attributes.len(), 1);
485485
assert_eq!(
486-
attributes.inner[0].value.attr_type(),
486+
attributes.first().unwrap().value.attr_type(),
487487
AttrType::Unknown(254)
488488
);
489489
}

src/parser/bgp/messages.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,21 +476,21 @@ impl BgpUpdateMessage {
476476
return false;
477477
}
478478

479-
if self.attributes.inner.is_empty() {
479+
if self.attributes.is_empty() {
480480
// no attributes, no prefixes:
481481
// case 1 end-of-rib
482482
return true;
483483
}
484484

485485
// has some attributes, it can only be withdrawal with no prefixes
486486

487-
if self.attributes.inner.len() > 1 {
487+
if self.attributes.len() > 1 {
488488
// has more than one attributes, not end-of-rib
489489
return false;
490490
}
491491

492492
// has only one attribute, check if it is withdrawal attribute
493-
if let AttributeValue::MpUnreachNlri(nlri) = &self.attributes.inner.first().unwrap().value {
493+
if let AttributeValue::MpUnreachNlri(nlri) = &self.attributes.first().unwrap().value {
494494
if nlri.prefixes.is_empty() {
495495
// the only attribute is MP_UNREACH_NLRI with no prefixes:
496496
// case 2 end-of-rib

src/parser/bmp/messages/route_monitoring.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ mod tests {
7575
bgp_message: BgpMessage::Update(msg),
7676
};
7777
#[cfg(feature = "parser")]
78-
let expected = "RouteMonitoring { bgp_message: Update(BgpUpdateMessage { withdrawn_prefixes: [], attributes: Attributes { inner: [], validation_warnings: [] }, announced_prefixes: [] }) }";
78+
let expected = "RouteMonitoring { bgp_message: Update(BgpUpdateMessage { withdrawn_prefixes: [], attributes: Attributes { inner: [], origin: None, as_path: None, next_hop: None, validation_warnings: [] }, announced_prefixes: [] }) }";
7979
#[cfg(not(feature = "parser"))]
80-
let expected = "RouteMonitoring { bgp_message: Update(BgpUpdateMessage { withdrawn_prefixes: [], attributes: Attributes { inner: [] }, announced_prefixes: [] }) }";
80+
let expected = "RouteMonitoring { bgp_message: Update(BgpUpdateMessage { withdrawn_prefixes: [], attributes: Attributes { inner: [], origin: None, as_path: None, next_hop: None }, announced_prefixes: [] }) }";
8181

8282
assert_eq!(format!("{mon_msg:?}"), expected);
8383
}

src/parser/mrt/messages/table_dump.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ impl TableDumpMessage {
145145

146146
// encode attributes
147147
let mut attr_bytes = BytesMut::new();
148-
for attr in &self.attributes.inner {
148+
for attr in self.attributes.attributes_iter() {
149149
// asn_len always 16 bites
150150
attr_bytes.extend(attr.encode(AsnLength::Bits16));
151151
}

0 commit comments

Comments
 (0)