summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-05-12 10:49:09 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2016-05-12 10:49:09 +0900
commit97e8f017cb4a3a38284d4657d1710608f5f28bd4 (patch)
treeaf25dbede45abaa94f4f5c7ef40e887a95d7a673
parente9c0c3e3e4e1f878361e25bf42684c4ddd22ad2e (diff)
table: fix Med comparison in best path selection
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--table/destination.go56
-rw-r--r--table/destination_test.go56
2 files changed, 98 insertions, 14 deletions
diff --git a/table/destination.go b/table/destination.go
index 1936dc01..3642cf7e 100644
--- a/table/destination.go
+++ b/table/destination.go
@@ -666,25 +666,53 @@ func compareByMED(path1, path2 *Path) *Path {
// RFC says lower MED is preferred over higher MED value.
// compare MED among not only same AS path but also all path,
// like bgp always-compare-med
- log.Debugf("enter compareByMED")
- getMed := func(path *Path) uint32 {
- attribute := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
- if attribute == nil {
+
+ isInternal := func() bool { return path1.GetAsPathLen() == 0 && path2.GetAsPathLen() == 0 }()
+
+ isSameAS := func() bool {
+ leftmostAS := func(path *Path) uint32 {
+ if aspath := path.GetAsPath(); aspath != nil {
+ asPathParam := aspath.Value
+ for i := len(asPathParam) - 1; i >= 0; i-- {
+ asPath := asPathParam[i].(*bgp.As4PathParam)
+ if asPath.Num == 0 {
+ continue
+ }
+ if asPath.Type == bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET || asPath.Type == bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ {
+ continue
+ }
+ return asPath.AS[asPath.Num-1]
+ }
+ }
return 0
}
- med := attribute.(*bgp.PathAttributeMultiExitDisc).Value
- return med
- }
+ return leftmostAS(path1) == leftmostAS(path2)
+ }()
+
+ if SelectionOptions.AlwaysCompareMed || isInternal || isSameAS {
+ log.Debugf("enter compareByMED")
+ getMed := func(path *Path) uint32 {
+ attribute := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
+ if attribute == nil {
+ return 0
+ }
+ med := attribute.(*bgp.PathAttributeMultiExitDisc).Value
+ return med
+ }
- med1 := getMed(path1)
- med2 := getMed(path2)
- log.Debugf("compareByMED -- med1: %d, med2: %d", med1, med2)
- if med1 == med2 {
+ med1 := getMed(path1)
+ med2 := getMed(path2)
+ log.Debugf("compareByMED -- med1: %d, med2: %d", med1, med2)
+ if med1 == med2 {
+ return nil
+ } else if med1 < med2 {
+ return path1
+ }
+ return path2
+ } else {
+ log.Debugf("skip compareByMED %v %v %v", SelectionOptions.AlwaysCompareMed, isInternal, isSameAS)
return nil
- } else if med1 < med2 {
- return path1
}
- return path2
}
func compareByASNumber(path1, path2 *Path) *Path {
diff --git a/table/destination_test.go b/table/destination_test.go
index c0666e21..275c4473 100644
--- a/table/destination_test.go
+++ b/table/destination_test.go
@@ -217,6 +217,62 @@ func TestImplicitWithdrawCalculate(t *testing.T) {
assert.Equal(t, len(d.knownPathList), 1)
}
+func TestMedTieBreaker(t *testing.T) {
+ nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0")
+
+ p0 := func() *Path {
+ aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003, 65004})})
+ attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(0)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ p1 := func() *Path {
+ aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003, 65004})})
+ attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ // same AS
+ assert.Equal(t, compareByMED(p0, p1), p0)
+
+ p2 := func() *Path {
+ aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003})})
+ attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ // different AS
+ assert.Equal(t, compareByMED(p0, p2), (*Path)(nil))
+
+ p3 := func() *Path {
+ aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint32{65003, 65004})})
+ attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(0)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ p4 := func() *Path {
+ aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint32{65005, 65006})})
+ attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ // ignore confed
+ assert.Equal(t, compareByMED(p3, p4), p3)
+
+ p5 := func() *Path {
+ attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeMultiExitDisc(0)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ p6 := func() *Path {
+ attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeMultiExitDisc(10)}
+ return NewPath(nil, nlri, false, attrs, time.Now(), false)
+ }()
+
+ // no aspath
+ assert.Equal(t, compareByMED(p5, p6), p5)
+}
+
func TestTimeTieBreaker(t *testing.T) {
origin := bgp.NewPathAttributeOrigin(0)
aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})}