diff options
Diffstat (limited to 'internal/pkg/table/destination_test.go')
-rw-r--r-- | internal/pkg/table/destination_test.go | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/internal/pkg/table/destination_test.go b/internal/pkg/table/destination_test.go new file mode 100644 index 00000000..110278fb --- /dev/null +++ b/internal/pkg/table/destination_test.go @@ -0,0 +1,442 @@ +// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +// implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package table + +import ( + //"fmt" + "fmt" + "net" + "testing" + "time" + + "github.com/osrg/gobgp/pkg/packet/bgp" + + "github.com/stretchr/testify/assert" +) + +func TestDestinationNewIPv4(t *testing.T) { + peerD := DestCreatePeer() + pathD := DestCreatePath(peerD) + ipv4d := NewDestination(pathD[0].GetNlri(), 0) + assert.NotNil(t, ipv4d) +} +func TestDestinationNewIPv6(t *testing.T) { + peerD := DestCreatePeer() + pathD := DestCreatePath(peerD) + ipv6d := NewDestination(pathD[0].GetNlri(), 0) + assert.NotNil(t, ipv6d) +} + +func TestDestinationSetRouteFamily(t *testing.T) { + dd := &Destination{} + dd.setRouteFamily(bgp.RF_IPv4_UC) + rf := dd.Family() + assert.Equal(t, rf, bgp.RF_IPv4_UC) +} +func TestDestinationGetRouteFamily(t *testing.T) { + dd := &Destination{} + dd.setRouteFamily(bgp.RF_IPv6_UC) + rf := dd.Family() + assert.Equal(t, rf, bgp.RF_IPv6_UC) +} +func TestDestinationSetNlri(t *testing.T) { + dd := &Destination{} + nlri := bgp.NewIPAddrPrefix(24, "13.2.3.1") + dd.setNlri(nlri) + r_nlri := dd.GetNlri() + assert.Equal(t, r_nlri, nlri) +} +func TestDestinationGetNlri(t *testing.T) { + dd := &Destination{} + nlri := bgp.NewIPAddrPrefix(24, "10.110.123.1") + dd.setNlri(nlri) + r_nlri := dd.GetNlri() + assert.Equal(t, r_nlri, nlri) +} + +func TestCalculate2(t *testing.T) { + + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") + med := bgp.NewPathAttributeMultiExitDisc(0) + pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} + nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") + + // peer1 sends normal update message 10.10.0.0/24 + update1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) + peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}} + path1 := ProcessMessage(update1, peer1, time.Now())[0] + + d := NewDestination(nlri, 0) + d.Calculate(path1) + + // suppose peer2 sends grammaatically correct but semantically flawed update message + // which has a withdrawal nlri not advertised before + update2 := bgp.NewBGPUpdateMessage([]*bgp.IPAddrPrefix{nlri}, pathAttributes, nil) + peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}} + path2 := ProcessMessage(update2, peer2, time.Now())[0] + assert.Equal(t, path2.IsWithdraw, true) + + d.Calculate(path2) + + // we have a path from peer1 here + assert.Equal(t, len(d.knownPathList), 1) + + // after that, new update with the same nlri comes from peer2 + update3 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) + path3 := ProcessMessage(update3, peer2, time.Now())[0] + assert.Equal(t, path3.IsWithdraw, false) + + d.Calculate(path3) + + // this time, we have paths from peer1 and peer2 + assert.Equal(t, len(d.knownPathList), 2) + + // now peer3 sends normal update message 10.10.0.0/24 + peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}} + update4 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) + path4 := ProcessMessage(update4, peer3, time.Now())[0] + + d.Calculate(path4) + + // we must have paths from peer1, peer2 and peer3 + assert.Equal(t, len(d.knownPathList), 3) +} + +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, 65005})}) + 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_CONFED_SEQ, []uint32{65003, 65004}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65003})}) + 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})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") + med := bgp.NewPathAttributeMultiExitDisc(0) + pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} + nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") + updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) + peer1 := &PeerInfo{AS: 2, LocalAS: 1, Address: net.IP{1, 1, 1, 1}, ID: net.IP{1, 1, 1, 1}} + path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] + + peer2 := &PeerInfo{AS: 2, LocalAS: 1, Address: net.IP{2, 2, 2, 2}, ID: net.IP{2, 2, 2, 2}} // weaker router-id + path2 := ProcessMessage(updateMsg, peer2, time.Now().Add(-1*time.Hour))[0] // older than path1 + + d := NewDestination(nlri, 0) + d.Calculate(path1) + d.Calculate(path2) + + assert.Equal(t, len(d.knownPathList), 2) + assert.Equal(t, true, d.GetBestPath("", 0).GetSource().ID.Equal(net.IP{2, 2, 2, 2})) // path from peer2 win + + // this option disables tie breaking by age + SelectionOptions.ExternalCompareRouterId = true + d = NewDestination(nlri, 0) + d.Calculate(path1) + d.Calculate(path2) + + assert.Equal(t, len(d.knownPathList), 2) + assert.Equal(t, true, d.GetBestPath("", 0).GetSource().ID.Equal(net.IP{1, 1, 1, 1})) // path from peer1 win +} + +func DestCreatePeer() []*PeerInfo { + peerD1 := &PeerInfo{AS: 65000} + peerD2 := &PeerInfo{AS: 65001} + peerD3 := &PeerInfo{AS: 65002} + peerD := []*PeerInfo{peerD1, peerD2, peerD3} + return peerD +} + +func DestCreatePath(peerD []*PeerInfo) []*Path { + bgpMsgD1 := updateMsgD1() + bgpMsgD2 := updateMsgD2() + bgpMsgD3 := updateMsgD3() + pathD := make([]*Path, 3) + for i, msg := range []*bgp.BGPMessage{bgpMsgD1, bgpMsgD2, bgpMsgD3} { + updateMsgD := msg.Body.(*bgp.BGPUpdate) + nlriList := updateMsgD.NLRI + pathAttributes := updateMsgD.PathAttributes + nlri_info := nlriList[0] + pathD[i] = NewPath(peerD[i], nlri_info, false, pathAttributes, time.Now(), false) + } + return pathD +} + +func updateMsgD1() *bgp.BGPMessage { + + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("192.168.50.1") + med := bgp.NewPathAttributeMultiExitDisc(0) + + pathAttributes := []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + + nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} + updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) + return updateMsg +} + +func updateMsgD2() *bgp.BGPMessage { + + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("192.168.100.1") + med := bgp.NewPathAttributeMultiExitDisc(100) + + pathAttributes := []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + + nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "20.20.20.0")} + updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) + return updateMsg +} +func updateMsgD3() *bgp.BGPMessage { + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("192.168.150.1") + med := bgp.NewPathAttributeMultiExitDisc(100) + + pathAttributes := []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + + nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "30.30.30.0")} + w1 := bgp.NewIPAddrPrefix(23, "40.40.40.0") + withdrawnRoutes := []*bgp.IPAddrPrefix{w1} + updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri) + UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) + return updateMsg +} + +func TestRadixkey(t *testing.T) { + assert.Equal(t, "000010100000001100100000", CidrToRadixkey("10.3.32.0/24")) + assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24)) + assert.Equal(t, "000010100000001100100000", IpToRadixkey(net.ParseIP("10.3.32.0").To4(), 24)) + assert.Equal(t, CidrToRadixkey("::ffff:0.0.0.0/96")+"000010100000001100100000", CidrToRadixkey("::ffff:10.3.32.0/120")) +} + +func TestIpToRadixkey(t *testing.T) { + for i := byte(0); i < 255; i += 3 { + for y := byte(1); y < 128; y *= 2 { + ip := net.IPv4(i, i+2, i+3, i-y) + for n := uint8(16); n <= 32; n += 2 { + exp := CidrToRadixkey(fmt.Sprintf("%v/%d", ip.To4(), n)) + got := IpToRadixkey(ip.To4(), n) + if exp != got { + t.Fatalf(`exp %v; got %v`, exp, got) + } + } + for n := uint8(116); n <= 128; n += 2 { + exp := CidrToRadixkey(fmt.Sprintf("::ffff:%v/%d", ip.To16(), n)) + got := IpToRadixkey(ip.To16(), n) + if exp != got { + t.Fatalf(`exp %v; got %v`, exp, got) + } + } + } + } +} + +func TestMultipath(t *testing.T) { + UseMultiplePaths.Enabled = true + origin := bgp.NewPathAttributeOrigin(0) + aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65000})} + aspath := bgp.NewPathAttributeAsPath(aspathParam) + nexthop := bgp.NewPathAttributeNextHop("192.168.150.1") + med := bgp.NewPathAttributeMultiExitDisc(100) + + pathAttributes := []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + + nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} + updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}, ID: net.IP{1, 1, 1, 1}} + path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] + peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}, ID: net.IP{2, 2, 2, 2}} + + med = bgp.NewPathAttributeMultiExitDisc(100) + nexthop = bgp.NewPathAttributeNextHop("192.168.150.2") + pathAttributes = []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + path2 := ProcessMessage(updateMsg, peer2, time.Now())[0] + + d := NewDestination(nlri[0], 0) + d.Calculate(path2) + + best, old, multi := d.Calculate(path1).GetChanges(GLOBAL_RIB_NAME, 0, false) + assert.NotNil(t, best) + assert.Equal(t, old, path2) + assert.Equal(t, len(multi), 2) + assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 2) + + path3 := path2.Clone(true) + dd := d.Calculate(path3) + best, old, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false) + assert.Nil(t, best) + assert.Equal(t, old, path1) + assert.Equal(t, len(multi), 1) + assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 1) + + peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}, ID: net.IP{3, 3, 3, 3}} + med = bgp.NewPathAttributeMultiExitDisc(50) + nexthop = bgp.NewPathAttributeNextHop("192.168.150.3") + pathAttributes = []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + path4 := ProcessMessage(updateMsg, peer3, time.Now())[0] + dd = d.Calculate(path4) + best, _, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false) + assert.NotNil(t, best) + assert.Equal(t, len(multi), 1) + assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 2) + + nexthop = bgp.NewPathAttributeNextHop("192.168.150.2") + pathAttributes = []bgp.PathAttributeInterface{ + origin, + aspath, + nexthop, + med, + } + updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) + path5 := ProcessMessage(updateMsg, peer2, time.Now())[0] + best, _, multi = d.Calculate(path5).GetChanges(GLOBAL_RIB_NAME, 0, false) + assert.NotNil(t, best) + assert.Equal(t, len(multi), 2) + assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME, 0)), 3) + + UseMultiplePaths.Enabled = false +} + +func TestIdMap(t *testing.T) { + d := NewDestination(bgp.NewIPAddrPrefix(24, "10.10.0.101"), 64) + for i := 0; ; i++ { + if id, err := d.localIdMap.FindandSetZeroBit(); err == nil { + assert.Equal(t, uint(i+1), id) + } else { + assert.Equal(t, i, 63) + break + } + } + d.localIdMap.Expand() + for i := 0; i < 64; i++ { + id, _ := d.localIdMap.FindandSetZeroBit() + assert.Equal(t, id, uint(64+i)) + } + _, err := d.localIdMap.FindandSetZeroBit() + assert.NotNil(t, err) +} + +func TestGetWithdrawnPath(t *testing.T) { + attrs := []bgp.PathAttributeInterface{ + bgp.NewPathAttributeOrigin(0), + } + p1 := NewPath(nil, bgp.NewIPAddrPrefix(24, "13.2.3.0"), false, attrs, time.Now(), false) + p2 := NewPath(nil, bgp.NewIPAddrPrefix(24, "13.2.4.0"), false, attrs, time.Now(), false) + p3 := NewPath(nil, bgp.NewIPAddrPrefix(24, "13.2.5.0"), false, attrs, time.Now(), false) + + u := &Update{ + KnownPathList: []*Path{p2}, + OldKnownPathList: []*Path{p1, p2, p3}, + } + + l := u.GetWithdrawnPath() + assert.Equal(t, len(l), 2) + assert.Equal(t, l[0].GetNlri(), p1.GetNlri()) +} |