@@ -12,7 +12,13 @@ use super::{
12
12
} ;
13
13
14
14
/// Wrapper type used for comparison and path selection.
15
- #[ derive( Copy , Clone , Debug ) ]
15
+ ///
16
+ /// Be aware that the `PartialEq` implementation of `OrdRoute` is specifically
17
+ /// tailored towards its `Ord` implementation, to do the BGP Decision Process.
18
+ /// Comparing two `OrdRoute`s, wrapping two routes with different sets of path
19
+ /// attributes, might still yield 'equal'. Instead, consider comparing on the
20
+ /// `PaMap` and/or `Tiebreakerinfo` directly (or [`fn inner`]).
21
+ #[ derive( Copy , Clone , Debug , Hash ) ]
16
22
pub struct OrdRoute < ' a , OS > {
17
23
pa_map : & ' a PaMap ,
18
24
tiebreakers : TiebreakerInfo ,
@@ -53,6 +59,22 @@ impl<'a, OS> OrdRoute<'a, OS> {
53
59
54
60
Ok ( self )
55
61
}
62
+
63
+
64
+ /// Returns the `TiebreakerInfo`.
65
+ pub fn tiebreakers ( & self ) -> TiebreakerInfo {
66
+ self . tiebreakers
67
+ }
68
+
69
+ /// Returns a reference to the Path Attributes.
70
+ pub fn pa_map ( & self ) -> & PaMap {
71
+ self . pa_map
72
+ }
73
+
74
+ /// Returns a tuple of the actual content of this OrdRoute.
75
+ pub fn inner ( & self ) -> ( TiebreakerInfo , & PaMap ) {
76
+ ( self . tiebreakers , self . pa_map ( ) )
77
+ }
56
78
}
57
79
58
80
impl < ' a , OS : OrdStrat > OrdRoute < ' a , OS > {
@@ -476,22 +498,28 @@ pub fn preferred<'a, OS: OrdStrat>(
476
498
cmp:: min ( a, b)
477
499
}
478
500
479
- pub fn best < ' a , OS : ' a + OrdStrat , I > ( it : I ) -> Option < I :: Item >
501
+ /// Selects the preferred ('best') route.
502
+ pub fn best < ' a , T , I , OS > ( it : I ) -> Option < T >
480
503
where
481
- I : Iterator < Item = OrdRoute < ' a , OS > >
504
+ T : Ord ,
505
+ I : Iterator < Item = T > ,
506
+ T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
482
507
{
483
508
it. min ( )
484
509
}
485
510
486
- pub fn best_with_strat < ' a , OS , AltOS , I > ( it : I )
511
+ /*
512
+ pub fn best_with_strat<'a, OS, AltOS, I, T1>(it: I)
487
513
-> Option<OrdRoute<'a, AltOS>>
488
514
where
489
515
OS: 'a + OrdStrat,
490
516
AltOS: 'a + OrdStrat,
491
- I : Iterator < Item = OrdRoute < ' a , OS > > ,
517
+ I: Iterator<Item = T1>,
518
+ T1: core::borrow::Borrow<OrdRoute<'a, OS>>
492
519
{
493
520
it.map(|r| r.into_strat()).min()
494
521
}
522
+ */
495
523
496
524
497
525
// XXX would this be convenient?
@@ -502,23 +530,23 @@ pub fn best_alt<'a, OS: OrdStrat>(
502
530
unimplemented ! ( )
503
531
}
504
532
505
- pub fn best_backup_vec < ' a , OS : OrdStrat > (
506
- it : impl Iterator < Item = OrdRoute < ' a , OS > >
507
- ) -> ( Option < OrdRoute < ' a , OS > > , Option < OrdRoute < ' a , OS > > )
508
- {
509
- let mut sorted = it. collect :: < Vec < _ > > ( ) ;
510
- sorted. sort ( ) ;
511
- let mut iter = sorted. into_iter ( ) ;
512
-
513
- let best = iter. next ( ) ;
514
- let backup = iter. next ( ) ;
515
-
516
- ( best, backup)
517
- }
518
-
519
- pub fn best_backup < T : Ord > (
533
+ /// Returns the 'best' and second-best path.
534
+ ///
535
+ /// If the iterator passed in contains no paths, `(None, None)` is returned.
536
+ /// If the iterator yields only a single item, that will be the 'best' path,
537
+ /// and the 'backup' will be None, i.e. `(Some(best), None)`.
538
+ ///
539
+ /// In all other cases (an iterator yielding two or more non-identical
540
+ /// values), both members of the tuple should be `Some(..)`.
541
+ ///
542
+ /// The returned 'best' path is the same as the path returned by [`fn best`].
543
+ pub fn best_backup < ' a , OS , T > (
520
544
it : impl Iterator < Item = T >
521
545
) -> ( Option < T > , Option < T > )
546
+ where
547
+ OS : OrdStrat ,
548
+ T : Ord ,
549
+ T : core:: borrow:: Borrow < OrdRoute < ' a , OS > >
522
550
{
523
551
let mut best = None ;
524
552
let mut backup = None ;
@@ -528,7 +556,7 @@ pub fn best_backup<T: Ord>(
528
556
None => { best = Some ( c) ; continue }
529
557
Some ( cur_best) => {
530
558
if c < cur_best {
531
- // c is preferred over current
559
+ // c is preferred over current best
532
560
best = Some ( c) ;
533
561
backup = Some ( cur_best) ;
534
562
continue ;
@@ -538,12 +566,35 @@ pub fn best_backup<T: Ord>(
538
566
539
567
// c is not better than best, now check backup
540
568
match backup. take ( ) {
541
- None => { backup = Some ( c) ; }
569
+ None => {
570
+ // Before we set the backup route, ensure it is not
571
+ // the same route as best.
572
+ // We compare the actual contents of the OrdRoute
573
+ // here, i.e. the TiebreakerInfo and PaMap. If we'd
574
+ // simply compare the OrdRoutes themselves, we'd be
575
+ // testing whether or not they are considered equal in
576
+ // terms of path preference, NOT in terms of content.
577
+ // If for example we have a candidate backup path with
578
+ // a different AS_PATH but of equal length as the best
579
+ // path, the OrdRoutes are considered equal even
580
+ // though the actual path attributes differ.
581
+ //
582
+
583
+ // Best is always Some at this point, unwrap is safe.
584
+ if best. as_ref ( ) . unwrap ( ) . borrow ( ) . inner ( ) != c. borrow ( ) . inner ( ) {
585
+ backup = Some ( c) ;
586
+ } }
542
587
Some ( cur_backup) => {
543
588
if c < cur_backup {
544
- // c is preferred over backup
545
- backup = Some ( c) ;
589
+ // c is preferred over current backup
590
+ // check if it is not the same route as 'best'
591
+ if best. as_ref ( ) != Some ( & c) {
592
+ backup = Some ( c) ;
593
+ } else {
594
+ backup = Some ( cur_backup) ;
595
+ }
546
596
} else {
597
+ // put it back in
547
598
backup = Some ( cur_backup) ;
548
599
}
549
600
@@ -556,7 +607,7 @@ pub fn best_backup<T: Ord>(
556
607
( best, backup)
557
608
}
558
609
559
-
610
+ /*
560
611
pub fn best_multistrat<'a, OS1: 'a + OrdStrat, OS2: 'a + OrdStrat, I>(it: I)
561
612
-> Option<(OrdRoute<'a, OS1>, OrdRoute<'a, OS2>)>
562
613
where
@@ -575,6 +626,33 @@ where
575
626
576
627
Some((res1, res2))
577
628
}
629
+ */
630
+
631
+ /*
632
+ pub fn best_multistrat<'a, I, T1, T2, OS1, OS2>(it: I) -> Option<(T1, T2)>
633
+ where
634
+ T1: Ord + core::borrow::Borrow<OrdRoute<'a, OS1>>,
635
+ T2: Ord,
636
+ OS1: OrdStrat,
637
+ OS2: OrdStrat,
638
+ I: Clone + Iterator<Item = T1>,
639
+ {
640
+ let res1 = best(it.clone());
641
+ let res1 = match res1 {
642
+ Some(r) => r,
643
+ None => return None
644
+ };
645
+
646
+ // Given that res1 is not None, `it` is non-empty.
647
+ // For a non-empty collection of OrdRoutes, there is always a best, so we
648
+ // can unwrap().
649
+ let res2 = best_with_strat::<'_, OS1, OS2, _>(it).unwrap();
650
+
651
+ Some((res1, res2))
652
+ }
653
+ */
654
+
655
+
578
656
579
657
580
658
//------------ Tests ---------------------------------------------------------
@@ -656,33 +734,38 @@ mod tests {
656
734
657
735
let mut b_pamap = PaMap :: empty ( ) ;
658
736
b_pamap. set ( Origin ( OriginType :: Egp ) ) ;
659
- b_pamap. set ( HopPath :: from ( [ 10 , 25 , 30 ] ) ) ;
737
+ b_pamap. set ( HopPath :: from ( [ 10 , 25 , 30 , 40 ] ) ) ;
660
738
b_pamap. set ( MultiExitDisc ( 50 ) ) ;
661
739
662
740
let mut c_pamap = PaMap :: empty ( ) ;
663
741
c_pamap. set ( Origin ( OriginType :: Egp ) ) ;
664
- c_pamap. set ( HopPath :: from ( [ 80 , 90 , 100 ] ) ) ;
742
+ c_pamap. set ( HopPath :: from ( [ 80 , 90 , 100 , 200 , 300 ] ) ) ;
665
743
666
744
let candidates = [
667
- OrdRoute :: rfc4271 ( & a_pamap, tiebreakers) . unwrap ( ) ,
668
- OrdRoute :: rfc4271 ( & b_pamap, tiebreakers) . unwrap ( ) ,
669
- OrdRoute :: rfc4271 ( & c_pamap, tiebreakers) . unwrap ( ) ,
745
+ OrdRoute :: skip_med ( & a_pamap, tiebreakers) . unwrap ( ) ,
746
+ OrdRoute :: skip_med ( & b_pamap, tiebreakers) . unwrap ( ) ,
747
+ OrdRoute :: skip_med ( & a_pamap, tiebreakers) . unwrap ( ) ,
748
+ //OrdRoute::skip_med(&c_pamap, tiebreakers).unwrap(),
670
749
] ;
671
750
672
- let best1 = best ( candidates. into_iter ( ) ) ;
673
- let ( best2, backup2) = best_backup_vec ( candidates. into_iter ( ) ) ;
674
- let ( best3, backup3) = best_backup ( candidates. into_iter ( ) ) ;
751
+ let best1 = best ( candidates. iter ( ) . cloned ( ) ) . unwrap ( ) ;
752
+ let ( best2, backup2) = best_backup ( candidates. iter ( ) ) ;
753
+ let ( best2, backup2) = ( best2. unwrap ( ) , backup2. unwrap ( ) ) ;
754
+
755
+ assert_eq ! ( best1. pa_map( ) , best2. pa_map( ) ) ;
756
+ assert_eq ! ( best1. tiebreakers( ) , best2. tiebreakers( ) ) ;
757
+
758
+ dbg ! ( & best2) ;
759
+ dbg ! ( & backup2) ;
675
760
676
- assert_eq ! ( best1, best2) ;
677
- assert_eq ! ( best2, best3) ;
678
- assert_eq ! ( backup2, backup3) ;
679
- assert_ne ! ( best2, backup2) ;
680
- assert_ne ! ( best3, backup3) ;
761
+ assert_ne ! (
762
+ ( best2. pa_map( ) , best2. tiebreakers( ) ) ,
763
+ ( backup2. pa_map( ) , backup2. tiebreakers( ) )
764
+ ) ;
681
765
682
- //dbg!(&best1);
683
- //dbg!(&backup2);
684
766
}
685
767
768
+ /*
686
769
#[test]
687
770
fn helpers_generic() {
688
771
let (a,b,c) = ("2".to_string(), "1".to_string(), "3".to_string());
@@ -692,4 +775,5 @@ mod tests {
692
775
assert_eq!(best, Some(&b));
693
776
assert_eq!(backup, Some(&a));
694
777
}
778
+ */
695
779
}
0 commit comments