@@ -135,7 +135,7 @@ pub trait OrdStrat {
135
135
}
136
136
137
137
/// Decision process strategy as described in RFC 4271.
138
- #[ derive( Debug ) ]
138
+ #[ derive( Copy , Clone , Debug ) ]
139
139
pub struct Rfc4271 ;
140
140
impl OrdStrat for Rfc4271 {
141
141
fn step_c < OS > ( a : & OrdRoute < OS > , b : & OrdRoute < OS > ) -> cmp:: Ordering {
@@ -170,7 +170,7 @@ impl OrdStrat for Rfc4271 {
170
170
}
171
171
172
172
/// Decision process strategy skipping comparison of Multi Exit Discriminator.
173
- #[ derive( Debug ) ]
173
+ #[ derive( Copy , Clone , Debug ) ]
174
174
pub struct SkipMed ;
175
175
176
176
impl OrdStrat for SkipMed {
@@ -449,6 +449,96 @@ impl fmt::Display for DecisionErrorType {
449
449
}
450
450
}
451
451
452
+
453
+ //------------ Helpers -------------------------------------------------------
454
+
455
+ pub fn preferred < ' a , OS : OrdStrat > (
456
+ a : OrdRoute < ' a , OS > , b : OrdRoute < ' a , OS >
457
+ ) -> OrdRoute < ' a , OS > {
458
+ cmp:: min ( a, b)
459
+ }
460
+
461
+ pub fn best < ' a , OS : ' a + OrdStrat , I > ( it : I ) -> Option < I :: Item >
462
+ where
463
+ I : Iterator < Item = & ' a OrdRoute < ' a , OS > >
464
+ {
465
+ it. min ( )
466
+ }
467
+
468
+
469
+ // XXX would this be convenient?
470
+ pub fn best_alt < ' a , OS : OrdStrat > (
471
+ _pamaps : impl Iterator < Item = & ' a PaMap > ,
472
+ _tiebreakers : impl Iterator < Item = TiebreakerInfo >
473
+ ) -> Option < OrdRoute < ' a , OS > > {
474
+ unimplemented ! ( )
475
+ }
476
+
477
+ pub fn best_backup_vec < ' a , OS : OrdStrat > (
478
+ it : impl Iterator < Item = & ' a OrdRoute < ' a , OS > >
479
+ ) -> ( Option < & ' a OrdRoute < ' a , OS > > , Option < & ' a OrdRoute < ' a , OS > > )
480
+ {
481
+ let mut sorted = it. collect :: < Vec < _ > > ( ) ;
482
+ sorted. sort ( ) ;
483
+ let mut iter = sorted. into_iter ( ) ;
484
+
485
+ let best = iter. next ( ) ;
486
+ let backup = iter. next ( ) ;
487
+
488
+ ( best, backup)
489
+ }
490
+
491
+ pub fn best_backup < ' a , OS : OrdStrat > (
492
+ it : impl Iterator < Item = & ' a OrdRoute < ' a , OS > >
493
+ ) -> ( Option < & ' a OrdRoute < ' a , OS > > , Option < & ' a OrdRoute < ' a , OS > > )
494
+ {
495
+ let mut best = None ;
496
+ let mut backup = None ;
497
+
498
+ for c in it {
499
+ match best. take ( ) {
500
+ None => { best = Some ( c) ; continue }
501
+ Some ( cur_best) => {
502
+ if c < cur_best {
503
+ // c is preferred over current
504
+ best = Some ( c) ;
505
+ backup = Some ( cur_best) ;
506
+ continue ;
507
+ }
508
+ // put it back in
509
+ best = Some ( cur_best) ;
510
+
511
+ // c is not better than best, now check backup
512
+ if let Some ( bkup) = backup. take ( ) {
513
+ if c < bkup {
514
+ // c is preferred over backup
515
+ backup = Some ( c) ;
516
+ continue ;
517
+ }
518
+ backup = Some ( bkup) ;
519
+ }
520
+ }
521
+ }
522
+ }
523
+
524
+ ( best, backup)
525
+ }
526
+
527
+ /*
528
+ pub fn best_multistrat<'a, OS1: OrdStrat, OS2: OrdStrat, I>(it: I)
529
+ -> (Option<&'a OrdRoute<'a, OS1>>, Option<&'a OrdRoute<'a, OS2>>)
530
+ where
531
+ I: Iterator<Item = &'a OrdRoute<'a, OS1>>,
532
+ I::Item: Copy
533
+ {
534
+ let res1 = best(it);
535
+ let it2 = it.copied().map(|r| r.into_strat());
536
+ let res2 = best::<'a, OS2, _>(it2);
537
+
538
+ (res1, res2)
539
+ }
540
+ */
541
+
452
542
//------------ Tests ---------------------------------------------------------
453
543
454
544
#[ cfg( test) ]
@@ -508,4 +598,48 @@ mod tests {
508
598
assert ! ( b == c) ;
509
599
assert ! ( a == c) ;
510
600
}
601
+
602
+
603
+ #[ test]
604
+ fn helpers ( ) {
605
+
606
+ let tiebreakers = TiebreakerInfo {
607
+ source : RouteSource :: Ebgp ,
608
+ degree_of_preference : None ,
609
+ local_asn : Asn :: from_u32 ( 100 ) ,
610
+ bgp_identifier : [ 0 , 0 , 0 , 0 ] . into ( ) ,
611
+ peer_addr : "::" . parse ( ) . unwrap ( ) ,
612
+ } ;
613
+
614
+ let mut a_pamap = PaMap :: empty ( ) ;
615
+ a_pamap. set ( Origin ( OriginType :: Egp ) ) ;
616
+ a_pamap. set ( HopPath :: from ( [ 10 , 20 , 30 ] ) ) ;
617
+ a_pamap. set ( MultiExitDisc ( 100 ) ) ;
618
+
619
+ let mut b_pamap = PaMap :: empty ( ) ;
620
+ b_pamap. set ( Origin ( OriginType :: Egp ) ) ;
621
+ b_pamap. set ( HopPath :: from ( [ 10 , 25 , 30 ] ) ) ;
622
+ b_pamap. set ( MultiExitDisc ( 50 ) ) ;
623
+
624
+ let mut c_pamap = PaMap :: empty ( ) ;
625
+ c_pamap. set ( Origin ( OriginType :: Egp ) ) ;
626
+ c_pamap. set ( HopPath :: from ( [ 80 , 90 , 100 ] ) ) ;
627
+
628
+ let candidates = [
629
+ OrdRoute :: rfc4271 ( & a_pamap, tiebreakers) . unwrap ( ) ,
630
+ OrdRoute :: rfc4271 ( & b_pamap, tiebreakers) . unwrap ( ) ,
631
+ OrdRoute :: rfc4271 ( & c_pamap, tiebreakers) . unwrap ( ) ,
632
+ ] ;
633
+
634
+ let best1 = best ( candidates. iter ( ) ) ;
635
+ let ( best2, backup2) = best_backup_vec ( candidates. iter ( ) ) ;
636
+ let ( best3, backup3) = best_backup ( candidates. iter ( ) ) ;
637
+
638
+ assert_eq ! ( best1, best2) ;
639
+ assert_eq ! ( best2, best3) ;
640
+ assert_eq ! ( backup2, backup3) ;
641
+ assert_ne ! ( best2, backup2) ;
642
+ assert_ne ! ( best3, backup3) ;
643
+ }
644
+
511
645
}
0 commit comments