@@ -5,6 +5,7 @@ mod origin;
55
66use crate :: models:: network:: * ;
77use bitflags:: bitflags;
8+ use itertools:: chain;
89use num_enum:: { FromPrimitive , IntoPrimitive } ;
910use std:: cmp:: Ordering ;
1011use std:: iter:: { FromIterator , Map } ;
@@ -138,25 +139,83 @@ pub fn get_deprecated_attr_type(attr_type: u8) -> Option<&'static str> {
138139pub struct Attributes {
139140 // Black box type to allow for later changes/optimizations. The most common attributes could be
140141 // added as fields to allow for easier lookup.
141- pub ( crate ) inner : Vec < Attribute > ,
142+ inner : Vec < Attribute > ,
143+
144+ // Direct fields for well-known mandatory path attributes.
145+ // ORIGIN is a well-known mandatory attribute
146+ origin : Option < Attribute > ,
147+ // AS_PATH is a well-known mandatory attribute
148+ as_path : Option < Attribute > ,
149+ // NEXT_HOP is a well-known mandatory attribute
150+ next_hop : Option < Attribute > ,
151+
142152 /// RFC 7606 validation warnings collected during parsing
143153 pub ( crate ) validation_warnings : Vec < BgpValidationWarning > ,
144154}
145155
156+ struct WellKnownMandatoryAndOtherAttributes {
157+ origin : Option < Attribute > ,
158+ as_path : Option < Attribute > ,
159+ next_hop : Option < Attribute > ,
160+ inner : Vec < Attribute > ,
161+ }
162+
163+ impl FromIterator < Attribute > for WellKnownMandatoryAndOtherAttributes {
164+ fn from_iter < T : IntoIterator < Item = Attribute > > ( iter : T ) -> Self {
165+ let iter = iter. into_iter ( ) ;
166+
167+ let mut origin = None ;
168+ let mut as_path = None ;
169+ let mut next_hop = None ;
170+ let mut inner = Vec :: with_capacity ( iter. size_hint ( ) . 0 . max ( 253 ) ) ;
171+
172+ for attr in iter {
173+ match attr. value . attr_type ( ) {
174+ AttrType :: ORIGIN => origin = Some ( attr) ,
175+ AttrType :: AS_PATH => as_path = Some ( attr) ,
176+ AttrType :: NEXT_HOP => next_hop = Some ( attr) ,
177+ _ => inner. push ( attr) ,
178+ }
179+ }
180+
181+ WellKnownMandatoryAndOtherAttributes {
182+ origin,
183+ as_path,
184+ next_hop,
185+ inner,
186+ }
187+ }
188+ }
189+
146190impl Attributes {
147191 pub fn has_attr ( & self , ty : AttrType ) -> bool {
148- self . inner . iter ( ) . any ( |x| x. value . attr_type ( ) == ty)
192+ match ty {
193+ AttrType :: ORIGIN => self . origin . is_some ( ) ,
194+ AttrType :: AS_PATH => self . as_path . is_some ( ) ,
195+ AttrType :: NEXT_HOP => self . next_hop . is_some ( ) ,
196+ _ => self . inner . iter ( ) . any ( |x| x. value . attr_type ( ) == ty)
197+ }
149198 }
150199
151200 pub fn get_attr ( & self , ty : AttrType ) -> Option < Attribute > {
152- self . inner
153- . iter ( )
154- . find ( |x| x. value . attr_type ( ) == ty)
155- . cloned ( )
201+ match ty {
202+ AttrType :: ORIGIN => self . origin . clone ( ) ,
203+ AttrType :: AS_PATH => self . as_path . clone ( ) ,
204+ AttrType :: NEXT_HOP => self . next_hop . clone ( ) ,
205+ _ => self . inner
206+ . iter ( )
207+ . find ( |x| x. value . attr_type ( ) == ty)
208+ . cloned ( )
209+ }
156210 }
157211
158212 pub fn add_attr ( & mut self , attr : Attribute ) {
159- self . inner . push ( attr) ;
213+ match attr. value . attr_type ( ) {
214+ AttrType :: ORIGIN => self . origin = Some ( attr) ,
215+ AttrType :: AS_PATH => self . as_path = Some ( attr) ,
216+ AttrType :: NEXT_HOP => self . next_hop = Some ( attr) ,
217+ _ => self . inner . push ( attr) ,
218+ }
160219 }
161220
162221 /// Add a validation warning to the attributes
@@ -177,9 +236,8 @@ impl Attributes {
177236 /// Get the `ORIGIN` attribute. In the event that this attribute is not present,
178237 /// [Origin::INCOMPLETE] will be returned instead.
179238 pub fn origin ( & self ) -> Origin {
180- self . inner
181- . iter ( )
182- . find_map ( |x| match & x. value {
239+ self . origin . as_ref ( )
240+ . and_then ( |x| match & x. value {
183241 AttributeValue :: Origin ( x) => Some ( * x) ,
184242 _ => None ,
185243 } )
@@ -199,10 +257,12 @@ impl Attributes {
199257 /// **Note**: Even when this attribute is not present, the next hop address may still be
200258 /// attainable from the `MP_REACH_NLRI` attribute.
201259 pub fn next_hop ( & self ) -> Option < IpAddr > {
202- self . inner . iter ( ) . find_map ( |x| match & x. value {
203- AttributeValue :: NextHop ( x) => Some ( * x) ,
204- _ => None ,
205- } )
260+ self . next_hop
261+ . as_ref ( )
262+ . and_then ( |x| match & x. value {
263+ AttributeValue :: NextHop ( x) => Some ( * x) ,
264+ _ => None ,
265+ } )
206266 }
207267
208268 pub fn multi_exit_discriminator ( & self ) -> Option < u32 > {
@@ -250,12 +310,12 @@ impl Attributes {
250310
251311 // These implementations are horribly inefficient, but they were super easy to write and use
252312 pub fn as_path ( & self ) -> Option < & AsPath > {
253- // Begin searching at the end of the attributes to increase the odds of finding an AS4
254- // attribute first.
255- self . inner . iter ( ) . rev ( ) . find_map ( |x| match & x. value {
256- AttributeValue :: AsPath { path, .. } => Some ( path) ,
257- _ => None ,
258- } )
313+ self . as_path
314+ . as_ref ( )
315+ . and_then ( |x| match & x. value {
316+ AttributeValue :: AsPath { path, .. } => Some ( path) ,
317+ _ => None ,
318+ } )
259319 }
260320
261321 pub fn get_reachable_nlri ( & self ) -> Option < & Nlri > {
@@ -288,7 +348,12 @@ impl Attributes {
288348 /// Get an iterator over the held [Attribute]s. If you do no not need attribute flags, consider
289349 /// using [Attributes::iter] instead.
290350 pub fn into_attributes_iter ( self ) -> impl Iterator < Item = Attribute > {
291- self . inner . into_iter ( )
351+ chain ! (
352+ self . as_path. into_iter( ) ,
353+ self . origin. into_iter( ) ,
354+ self . next_hop. into_iter( ) ,
355+ self . inner. into_iter( ) ,
356+ )
292357 }
293358}
294359
@@ -326,17 +391,27 @@ impl Iterator for MetaCommunitiesIter<'_> {
326391
327392impl FromIterator < Attribute > for Attributes {
328393 fn from_iter < T : IntoIterator < Item = Attribute > > ( iter : T ) -> Self {
394+ let attrs = WellKnownMandatoryAndOtherAttributes :: from_iter ( iter) ;
395+
329396 Attributes {
330- inner : iter. into_iter ( ) . collect ( ) ,
397+ origin : attrs. origin ,
398+ as_path : attrs. as_path ,
399+ next_hop : attrs. next_hop ,
400+ inner : attrs. inner ,
331401 validation_warnings : Vec :: new ( ) ,
332402 }
333403 }
334404}
335405
336406impl From < Vec < Attribute > > for Attributes {
337407 fn from ( value : Vec < Attribute > ) -> Self {
408+ let attrs = WellKnownMandatoryAndOtherAttributes :: from_iter ( value. into_iter ( ) ) ;
409+
338410 Attributes {
339- inner : value,
411+ origin : attrs. origin ,
412+ as_path : attrs. as_path ,
413+ next_hop : attrs. next_hop ,
414+ inner : attrs. inner ,
340415 validation_warnings : Vec :: new ( ) ,
341416 }
342417 }
@@ -356,14 +431,20 @@ impl Extend<AttributeValue> for Attributes {
356431
357432impl FromIterator < AttributeValue > for Attributes {
358433 fn from_iter < T : IntoIterator < Item = AttributeValue > > ( iter : T ) -> Self {
359- Attributes {
360- inner : iter
434+ let attrs = WellKnownMandatoryAndOtherAttributes :: from_iter (
435+ iter
361436 . into_iter ( )
362437 . map ( |value| Attribute {
363438 value,
364439 flag : AttrFlags :: empty ( ) ,
365440 } )
366- . collect ( ) ,
441+ ) ;
442+
443+ Attributes {
444+ origin : attrs. origin ,
445+ as_path : attrs. as_path ,
446+ next_hop : attrs. next_hop ,
447+ inner : attrs. inner ,
367448 validation_warnings : Vec :: new ( ) ,
368449 }
369450 }
@@ -383,7 +464,14 @@ impl<'a> IntoIterator for &'a Attributes {
383464 type IntoIter = Map < Iter < ' a , Attribute > , fn ( & Attribute ) -> & AttributeValue > ;
384465
385466 fn into_iter ( self ) -> Self :: IntoIter {
386- self . inner . iter ( ) . map ( |x| & x. value )
467+ let tmp: Vec < _ > = chain ! (
468+ self . as_path. iter( ) ,
469+ self . origin. iter( ) ,
470+ self . next_hop. iter( ) ,
471+ self . inner. iter( )
472+ ) . collect ( ) ;
473+
474+ tmp. as_slice ( ) . into_iter ( ) . map ( |x| & x. value )
387475 }
388476}
389477
0 commit comments