Skip to content

Commit c55feaf

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

File tree

5 files changed

+93
-44
lines changed

5 files changed

+93
-44
lines changed

src/models/bgp/attributes/mod.rs

Lines changed: 84 additions & 35 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::*;
@@ -187,13 +185,19 @@ impl FromIterator<Attribute> for WellKnownMandatoryAndOtherAttributes {
187185
}
188186
}
189187

188+
impl From<Vec<Attribute>> for WellKnownMandatoryAndOtherAttributes {
189+
fn from(attributes: Vec<Attribute>) -> Self {
190+
attributes.into_iter().collect()
191+
}
192+
}
193+
190194
impl Attributes {
191195
pub fn has_attr(&self, ty: AttrType) -> bool {
192196
match ty {
193197
AttrType::ORIGIN => self.origin.is_some(),
194198
AttrType::AS_PATH => self.as_path.is_some(),
195199
AttrType::NEXT_HOP => self.next_hop.is_some(),
196-
_ => self.inner.iter().any(|x| x.value.attr_type() == ty)
200+
_ => self.inner.iter().any(|x| x.value.attr_type() == ty),
197201
}
198202
}
199203

@@ -202,10 +206,11 @@ impl Attributes {
202206
AttrType::ORIGIN => self.origin.clone(),
203207
AttrType::AS_PATH => self.as_path.clone(),
204208
AttrType::NEXT_HOP => self.next_hop.clone(),
205-
_ => self.inner
206-
.iter()
207-
.find(|x| x.value.attr_type() == ty)
208-
.cloned()
209+
_ => self
210+
.inner
211+
.iter()
212+
.find(|x| x.value.attr_type() == ty)
213+
.cloned(),
209214
}
210215
}
211216

@@ -236,7 +241,8 @@ impl Attributes {
236241
/// Get the `ORIGIN` attribute. In the event that this attribute is not present,
237242
/// [Origin::INCOMPLETE] will be returned instead.
238243
pub fn origin(&self) -> Origin {
239-
self.origin.as_ref()
244+
self.origin
245+
.as_ref()
240246
.and_then(|x| match &x.value {
241247
AttributeValue::Origin(x) => Some(*x),
242248
_ => None,
@@ -257,12 +263,10 @@ impl Attributes {
257263
/// **Note**: Even when this attribute is not present, the next hop address may still be
258264
/// attainable from the `MP_REACH_NLRI` attribute.
259265
pub fn next_hop(&self) -> Option<IpAddr> {
260-
self.next_hop
261-
.as_ref()
262-
.and_then(|x| match &x.value {
263-
AttributeValue::NextHop(x) => Some(*x),
264-
_ => None,
265-
})
266+
self.next_hop.as_ref().and_then(|x| match &x.value {
267+
AttributeValue::NextHop(x) => Some(*x),
268+
_ => None,
269+
})
266270
}
267271

268272
pub fn multi_exit_discriminator(&self) -> Option<u32> {
@@ -310,12 +314,10 @@ impl Attributes {
310314

311315
// These implementations are horribly inefficient, but they were super easy to write and use
312316
pub fn as_path(&self) -> Option<&AsPath> {
313-
self.as_path
314-
.as_ref()
315-
.and_then(|x| match &x.value {
316-
AttributeValue::AsPath { path, .. } => Some(path),
317-
_ => None,
318-
})
317+
self.as_path.as_ref().and_then(|x| match &x.value {
318+
AttributeValue::AsPath { path, .. } => Some(path),
319+
_ => None,
320+
})
319321
}
320322

321323
pub fn get_reachable_nlri(&self) -> Option<&Nlri> {
@@ -339,12 +341,45 @@ impl Attributes {
339341
}
340342
}
341343

344+
/// Count the total number of attributes (including well-known mandatory attributes)
345+
pub fn len(&self) -> usize {
346+
self.origin.iter().count()
347+
+ self.as_path.iter().count()
348+
+ self.next_hop.iter().count()
349+
+ self.inner.len()
350+
}
351+
352+
/// Check if there are no attributes
353+
pub fn is_empty(&self) -> bool {
354+
self.len() == 0
355+
}
356+
357+
/// Get the first attribute if any exists
358+
pub fn first(&self) -> Option<&Attribute> {
359+
self.origin
360+
.as_ref()
361+
.or(self.as_path.as_ref())
362+
.or(self.next_hop.as_ref())
363+
.or(self.inner.first())
364+
}
365+
342366
/// Get an iterator over the held [AttributeValue]s. If you also need attribute flags, consider
343367
/// using [Attributes::into_attributes_iter] instead.
344368
pub fn iter(&self) -> <&'_ Self as IntoIterator>::IntoIter {
345369
self.into_iter()
346370
}
347371

372+
/// Get an iterator over references to the held [Attribute]s. If you do not need attribute flags,
373+
/// consider using [Attributes::iter] instead.
374+
pub fn attributes_iter(&self) -> impl Iterator<Item = &Attribute> {
375+
chain!(
376+
self.as_path.iter(),
377+
self.origin.iter(),
378+
self.next_hop.iter(),
379+
self.inner.iter(),
380+
)
381+
}
382+
348383
/// Get an iterator over the held [Attribute]s. If you do no not need attribute flags, consider
349384
/// using [Attributes::iter] instead.
350385
pub fn into_attributes_iter(self) -> impl Iterator<Item = Attribute> {
@@ -431,14 +466,13 @@ impl Extend<AttributeValue> for Attributes {
431466

432467
impl FromIterator<AttributeValue> for Attributes {
433468
fn from_iter<T: IntoIterator<Item = AttributeValue>>(iter: T) -> Self {
434-
let attrs = WellKnownMandatoryAndOtherAttributes::from_iter(
435-
iter
436-
.into_iter()
437-
.map(|value| Attribute {
469+
let attrs =
470+
WellKnownMandatoryAndOtherAttributes::from_iter(iter.into_iter().map(|value| {
471+
Attribute {
438472
value,
439473
flag: AttrFlags::empty(),
440-
})
441-
);
474+
}
475+
}));
442476

443477
Attributes {
444478
origin: attrs.origin,
@@ -452,26 +486,35 @@ impl FromIterator<AttributeValue> for Attributes {
452486

453487
impl IntoIterator for Attributes {
454488
type Item = AttributeValue;
455-
type IntoIter = Map<IntoIter<Attribute>, fn(Attribute) -> AttributeValue>;
489+
type IntoIter = std::vec::IntoIter<AttributeValue>;
456490

457491
fn into_iter(self) -> Self::IntoIter {
458-
self.inner.into_iter().map(|x| x.value)
492+
chain!(
493+
self.as_path.into_iter(),
494+
self.origin.into_iter(),
495+
self.next_hop.into_iter(),
496+
self.inner.into_iter()
497+
)
498+
.map(|x| x.value)
499+
.collect::<Vec<_>>()
500+
.into_iter()
459501
}
460502
}
461503

462504
impl<'a> IntoIterator for &'a Attributes {
463505
type Item = &'a AttributeValue;
464-
type IntoIter = Map<Iter<'a, Attribute>, fn(&Attribute) -> &AttributeValue>;
506+
type IntoIter = std::vec::IntoIter<&'a AttributeValue>;
465507

466508
fn into_iter(self) -> Self::IntoIter {
467-
let tmp: Vec<_> = chain!(
509+
chain!(
468510
self.as_path.iter(),
469511
self.origin.iter(),
470512
self.next_hop.iter(),
471513
self.inner.iter()
472-
).collect();
473-
474-
tmp.as_slice().into_iter().map(|x| &x.value)
514+
)
515+
.map(|x| &x.value)
516+
.collect::<Vec<_>>()
517+
.into_iter()
475518
}
476519
}
477520

@@ -494,8 +537,14 @@ mod serde_impl {
494537
where
495538
D: Deserializer<'de>,
496539
{
540+
let attributes = <Vec<Attribute>>::deserialize(deserializer)?;
541+
let well_known_and_others = WellKnownMandatoryAndOtherAttributes::from(attributes);
542+
497543
Ok(Attributes {
498-
inner: <Vec<Attribute>>::deserialize(deserializer)?,
544+
inner: well_known_and_others.inner,
545+
origin: well_known_and_others.origin,
546+
as_path: well_known_and_others.as_path,
547+
next_hop: well_known_and_others.next_hop,
499548
validation_warnings: Vec::new(),
500549
})
501550
}

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)