diff options
-rw-r--r-- | table/destination.go | 56 | ||||
-rw-r--r-- | table/destination_test.go | 56 |
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})} |