summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gobgp/cmd/mrt.go7
-rw-r--r--server/server.go218
-rw-r--r--server/server_test.go11
-rw-r--r--table/destination.go171
-rw-r--r--table/destination_test.go43
-rw-r--r--table/table.go31
-rw-r--r--table/table_manager.go89
-rw-r--r--table/table_manager_test.go6
8 files changed, 215 insertions, 361 deletions
diff --git a/gobgp/cmd/mrt.go b/gobgp/cmd/mrt.go
index acafbc33..d9be3d1c 100644
--- a/gobgp/cmd/mrt.go
+++ b/gobgp/cmd/mrt.go
@@ -142,11 +142,8 @@ func injectMrt() error {
}
if mrtOpts.Best {
- dst := table.NewDestination(nlri, 0)
- for _, p := range paths {
- dst.AddNewPath(p)
- }
- best, _, _ := dst.Calculate().GetChanges(table.GLOBAL_RIB_NAME, 0, false)
+ dst := table.NewDestination(nlri, 0, paths...)
+ best, _, _ := dst.Calculate(paths[0]).GetChanges(table.GLOBAL_RIB_NAME, 0, false)
if best == nil {
exitWithError(fmt.Errorf("Can't find the best %v", nlri))
}
diff --git a/server/server.go b/server/server.go
index 47bebd7b..e766d84e 100644
--- a/server/server.go
+++ b/server/server.go
@@ -545,66 +545,6 @@ func (server *BgpServer) notifyPostPolicyUpdateWatcher(peer *Peer, pathList []*t
server.notifyWatcher(WATCH_EVENT_TYPE_POST_UPDATE, ev)
}
-func dstsToPaths(id string, as uint32, dsts []*table.Destination, addpath bool) ([]*table.Path, []*table.Path, [][]*table.Path) {
- if table.SelectionOptions.DisableBestPathSelection {
- // Note: If best path selection disabled, there is no best path.
- return nil, nil, nil
- }
- bestList := make([]*table.Path, 0, len(dsts))
- oldList := make([]*table.Path, 0, len(dsts))
- mpathList := make([][]*table.Path, 0, len(dsts))
-
- for _, dst := range dsts {
- if addpath {
- bestList = append(bestList, dst.GetAddPathChanges(id)...)
- } else {
- best, old, mpath := dst.GetChanges(id, as, false)
- bestList = append(bestList, best)
- oldList = append(oldList, old)
- if mpath != nil {
- mpathList = append(mpathList, mpath)
- }
- }
- }
- if addpath {
- oldList = nil
- }
- return bestList, oldList, mpathList
-}
-
-func (server *BgpServer) dropPeerAllRoutes(peer *Peer, families []bgp.RouteFamily) {
- var gBestList, bestList []*table.Path
- var mpathList [][]*table.Path
- families = peer.toGlobalFamilies(families)
- rib := server.globalRib
- if peer.isRouteServerClient() {
- rib = server.rsRib
- }
- for _, rf := range families {
- dsts := rib.DeletePathsByPeer(peer.fsm.peerInfo, rf)
- if !peer.isRouteServerClient() {
- gBestList, _, mpathList = dstsToPaths(table.GLOBAL_RIB_NAME, 0, dsts, false)
- server.notifyBestWatcher(gBestList, mpathList)
- }
-
- for _, targetPeer := range server.neighborMap {
- if peer.isRouteServerClient() != targetPeer.isRouteServerClient() || targetPeer == peer {
- continue
- }
- if targetPeer.isAddPathSendEnabled(rf) {
- bestList, _, _ = dstsToPaths(targetPeer.TableID(), targetPeer.AS(), dsts, true)
- } else if targetPeer.isRouteServerClient() {
- bestList, _, _ = dstsToPaths(targetPeer.TableID(), targetPeer.AS(), dsts, false)
- } else {
- bestList = gBestList
- }
- if paths := targetPeer.processOutgoingPaths(bestList, nil); len(paths) > 0 {
- sendFsmOutgoingMsg(targetPeer, paths, nil, false)
- }
- }
- }
-}
-
func createWatchEventPeerState(peer *Peer) *WatchEventPeerState {
_, rport := peer.fsm.RemoteHostPort()
laddr, lport := peer.fsm.LocalHostPort()
@@ -662,47 +602,38 @@ func (server *BgpServer) notifyRecvMessageWatcher(peer *Peer, timestamp time.Tim
}
func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) {
- var dsts []*table.Destination
-
- var gBestList, gOldList []*table.Path
- var mpathList [][]*table.Path
+ rs := peer != nil && peer.isRouteServerClient()
+ vrf := !rs && peer != nil && peer.fsm.pConf.Config.Vrf != ""
+ var policyOptions *table.PolicyOptions
+ if !rs && peer != nil {
+ policyOptions = &table.PolicyOptions{
+ Info: peer.fsm.peerInfo,
+ }
+ } else {
+ policyOptions = nil
+ }
+ tableId := table.GLOBAL_RIB_NAME
rib := server.globalRib
+ if rs {
+ tableId = peer.TableID()
+ rib = server.rsRib
+ }
- if peer != nil && peer.fsm.pConf.Config.Vrf != "" {
- vrf := server.globalRib.Vrfs[peer.fsm.pConf.Config.Vrf]
- for idx, path := range pathList {
- pathList[idx] = path.ToGlobal(vrf)
+ for _, path := range pathList {
+ if vrf {
+ path = path.ToGlobal(rib.Vrfs[peer.fsm.pConf.Config.Vrf])
}
- }
- if peer != nil && peer.isRouteServerClient() {
- rib = server.rsRib
- for idx, path := range pathList {
- if p := server.policy.ApplyPolicy(peer.TableID(), table.POLICY_DIRECTION_IMPORT, path, nil); p != nil {
- path = p
- } else {
- path = path.Clone(true)
- }
- pathList[idx] = path
+ if p := server.policy.ApplyPolicy(tableId, table.POLICY_DIRECTION_IMPORT, path, policyOptions); p != nil {
+ path = p
+ } else {
+ path = path.Clone(true)
}
- dsts = rib.ProcessPaths(pathList)
- } else {
- for idx, path := range pathList {
- var options *table.PolicyOptions
- if peer != nil {
- options = &table.PolicyOptions{
- Info: peer.fsm.peerInfo,
- }
- } else {
- options = nil
- }
- if p := server.policy.ApplyPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT, path, options); p != nil {
- path = p
- } else {
- path = path.Clone(true)
- }
- pathList[idx] = path
+
+ if !rs {
+ server.notifyPostPolicyUpdateWatcher(peer, []*table.Path{path})
+
// RFC4684 Constrained Route Distribution 6. Operation
//
// When a BGP speaker receives a BGP UPDATE that advertises or withdraws
@@ -726,7 +657,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) {
if path.IsWithdraw {
candidates, _ = peer.getBestFromLocal(peer.configuredRFlist())
} else {
- candidates = rib.GetBestPathList(peer.TableID(), 0, fs)
+ candidates = server.globalRib.GetBestPathList(peer.TableID(), 0, fs)
}
paths := make([]*table.Path, 0, len(candidates))
for _, p := range candidates {
@@ -748,47 +679,73 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) {
sendFsmOutgoingMsg(peer, paths, nil, false)
}
}
- server.notifyPostPolicyUpdateWatcher(peer, pathList)
- dsts = rib.ProcessPaths(pathList)
- gBestList, gOldList, mpathList = dstsToPaths(table.GLOBAL_RIB_NAME, 0, dsts, false)
- server.notifyBestWatcher(gBestList, mpathList)
+ if dsts := rib.Update(path); len(dsts) > 0 {
+ server.propagateUpdateToNeighbors(peer, path, dsts, true)
+ }
}
-
- server.propagateUpdateToNeighbors(peer, dsts, gBestList, gOldList)
}
-func (server *BgpServer) propagateUpdateToNeighbors(peer *Peer, dsts []*table.Destination, gBestList, gOldList []*table.Path) {
- if table.SelectionOptions.DisableBestPathSelection {
- // Note: If best path selection disabled, no best path to propagate.
- return
+func (server *BgpServer) dropPeerAllRoutes(peer *Peer, families []bgp.RouteFamily) {
+ rib := server.globalRib
+ if peer.isRouteServerClient() {
+ rib = server.rsRib
}
- families := make(map[bgp.RouteFamily][]*table.Destination)
+ for _, family := range peer.toGlobalFamilies(families) {
+ for _, path := range rib.GetPathListByPeer(peer.fsm.peerInfo, family) {
+ p := path.Clone(true)
+ if dsts := rib.Update(p); len(dsts) > 0 {
+ server.propagateUpdateToNeighbors(peer, p, dsts, false)
+ }
+ }
+ }
+}
+
+func dstsToPaths(id string, as uint32, dsts []*table.Destination) ([]*table.Path, []*table.Path, [][]*table.Path) {
+ bestList := make([]*table.Path, 0, len(dsts))
+ oldList := make([]*table.Path, 0, len(dsts))
+ mpathList := make([][]*table.Path, 0, len(dsts))
+
for _, dst := range dsts {
- family := dst.Family()
- if families[family] == nil {
- families[family] = make([]*table.Destination, 0, len(dsts))
+ best, old, mpath := dst.GetChanges(id, as, false)
+ bestList = append(bestList, best)
+ oldList = append(oldList, old)
+ if mpath != nil {
+ mpathList = append(mpathList, mpath)
}
- families[family] = append(families[family], dst)
}
+ return bestList, oldList, mpathList
+}
- var bestList, oldList []*table.Path
- for family, l := range families {
- for _, targetPeer := range server.neighborMap {
- if (peer == nil && targetPeer.isRouteServerClient()) || (peer != nil && peer.isRouteServerClient() != targetPeer.isRouteServerClient()) {
- continue
- }
- if targetPeer.isAddPathSendEnabled(family) {
- bestList, oldList, _ = dstsToPaths(targetPeer.TableID(), targetPeer.AS(), l, true)
- } else if targetPeer.isRouteServerClient() {
- bestList, oldList, _ = dstsToPaths(targetPeer.TableID(), targetPeer.AS(), l, false)
- } else {
- bestList = gBestList
- oldList = gOldList
- }
- if paths := targetPeer.processOutgoingPaths(bestList, oldList); len(paths) > 0 {
- sendFsmOutgoingMsg(targetPeer, paths, nil, false)
- }
+func (server *BgpServer) propagateUpdateToNeighbors(source *Peer, newPath *table.Path, dsts []*table.Destination, needOld bool) {
+ if table.SelectionOptions.DisableBestPathSelection {
+ return
+ }
+ var gBestList, gOldList, bestList, oldList []*table.Path
+ var mpathList [][]*table.Path
+ if source == nil || !source.isRouteServerClient() {
+ gBestList, gOldList, mpathList = dstsToPaths(table.GLOBAL_RIB_NAME, 0, dsts)
+ server.notifyBestWatcher(gBestList, mpathList)
+ }
+ family := newPath.GetRouteFamily()
+ for _, targetPeer := range server.neighborMap {
+ if (source == nil && targetPeer.isRouteServerClient()) || (source != nil && source.isRouteServerClient() != targetPeer.isRouteServerClient()) {
+ continue
+ }
+ if targetPeer.isAddPathSendEnabled(family) {
+ bestList = []*table.Path{newPath}
+ oldList = nil
+ } else if targetPeer.isRouteServerClient() {
+ bestList, oldList, _ = dstsToPaths(targetPeer.TableID(), targetPeer.AS(), dsts)
+ } else {
+ bestList = gBestList
+ oldList = gOldList
+ }
+ if !needOld {
+ oldList = nil
+ }
+ if paths := targetPeer.processOutgoingPaths(bestList, oldList); len(paths) > 0 {
+ sendFsmOutgoingMsg(targetPeer, paths, nil, false)
}
}
}
@@ -1359,10 +1316,7 @@ func (s *BgpServer) UpdatePath(vrfId string, pathList []*table.Path) error {
if err := s.fixupApiPath(vrfId, pathList); err != nil {
return err
}
- dsts := s.globalRib.ProcessPaths(pathList)
- gBestList, gOldList, gMPathList := dstsToPaths(table.GLOBAL_RIB_NAME, 0, dsts, false)
- s.notifyBestWatcher(gBestList, gMPathList)
- s.propagateUpdateToNeighbors(nil, dsts, gBestList, gOldList)
+ s.propagateUpdate(nil, pathList)
return nil
}, true)
return err
diff --git a/server/server_test.go b/server/server_test.go
index 7eaea7b7..720202d0 100644
--- a/server/server_test.go
+++ b/server/server_test.go
@@ -269,7 +269,11 @@ func newPeerandInfo(myAs, as uint32, address string, rib *table.TableManager) (*
}
func process(rib *table.TableManager, l []*table.Path) (*table.Path, *table.Path) {
- news, olds, _ := dstsToPaths(table.GLOBAL_RIB_NAME, 0, rib.ProcessPaths(l), false)
+ dsts := make([]*table.Destination, 0)
+ for _, path := range l {
+ dsts = append(dsts, rib.Update(path)...)
+ }
+ news, olds, _ := dstsToPaths(table.GLOBAL_RIB_NAME, 0, dsts)
if len(news) != 1 {
panic("can't handle multiple paths")
}
@@ -297,8 +301,9 @@ func TestFilterpathWitheBGP(t *testing.T) {
path1 := table.NewPath(pi1, nlri, false, pa1, time.Now(), false)
path2 := table.NewPath(pi2, nlri, false, pa2, time.Now(), false)
-
- new, old := process(rib, []*table.Path{path1, path2})
+ rib.Update(path2)
+ d := rib.Update(path1)
+ new, old, _ := d[0].GetChanges(table.GLOBAL_RIB_NAME, 0, false)
assert.Equal(t, new, path1)
filterpath(p1, new, old)
filterpath(p2, new, old)
diff --git a/table/destination.go b/table/destination.go
index 32169f59..6dac57db 100644
--- a/table/destination.go
+++ b/table/destination.go
@@ -353,16 +353,6 @@ func (dd *Destination) GetChanges(id string, as uint32, peerDown bool) (*Path, *
return best, old, multi
}
-func (dd *Destination) AddWithdraw(withdraw *Path) {
- dd.validatePath(withdraw)
- dd.withdrawList = append(dd.withdrawList, withdraw)
-}
-
-func (dd *Destination) AddNewPath(newPath *Path) {
- dd.validatePath(newPath)
- dd.newPathList = append(dd.newPathList, newPath)
-}
-
func (dd *Destination) validatePath(path *Path) {
if path == nil || path.GetRouteFamily() != dd.routeFamily {
@@ -379,21 +369,25 @@ func (dd *Destination) validatePath(path *Path) {
//
// Modifies destination's state related to stored paths. Removes withdrawn
// paths from known paths. Also, adds new paths to known paths.
-func (dest *Destination) Calculate() *Destination {
- oldKnownPathList := dest.knownPathList
- newPathList := dest.newPathList
- // First remove the withdrawn paths.
- withdrawn := dest.explicitWithdraw()
- // Do implicit withdrawal
- dest.implicitWithdraw()
-
- for _, path := range withdrawn {
- if id := path.GetNlri().PathLocalIdentifier(); id != 0 {
- dest.localIdMap.Unflag(uint(id))
+func (dest *Destination) Calculate(newPath *Path) *Destination {
+ oldKnownPathList := make([]*Path, len(dest.knownPathList))
+ copy(oldKnownPathList, dest.knownPathList)
+ newPathList := make([]*Path, 0)
+ withdrawList := make([]*Path, 0)
+
+ if newPath.IsWithdraw {
+ p := dest.explicitWithdraw(newPath)
+ if p != nil {
+ if id := p.GetNlri().PathLocalIdentifier(); id != 0 {
+ dest.localIdMap.Unflag(uint(id))
+ }
}
+ withdrawList = append(withdrawList, newPath)
+ } else {
+ dest.implicitWithdraw(newPath)
+ dest.knownPathList = append(dest.knownPathList, newPath)
+ newPathList = append(newPathList, newPath)
}
- // Collect all new paths into known paths.
- dest.knownPathList = append(dest.knownPathList, dest.newPathList...)
for _, path := range dest.knownPathList {
if path.GetNlri().PathLocalIdentifier() == 0 {
@@ -405,8 +399,6 @@ func (dest *Destination) Calculate() *Destination {
path.GetNlri().SetPathLocalIdentifier(uint32(id))
}
}
- // Clear new paths as we copied them.
- dest.newPathList = make([]*Path, 0)
// Compute new best path
dest.computeKnownBestPath()
@@ -416,7 +408,7 @@ func (dest *Destination) Calculate() *Destination {
knownPathList: dest.knownPathList,
oldKnownPathList: oldKnownPathList,
newPathList: newPathList,
- withdrawList: withdrawn,
+ withdrawList: withdrawList,
}
}
@@ -428,113 +420,76 @@ func (dest *Destination) Calculate() *Destination {
// we can receive withdraws for such paths and withdrawals may not be
// stopped by the same policies.
//
-func (dest *Destination) explicitWithdraw() paths {
-
- // If we have no withdrawals, we have nothing to do.
- if len(dest.withdrawList) == 0 {
- return nil
- }
-
+func (dest *Destination) explicitWithdraw(withdraw *Path) *Path {
log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": dest.GetNlri().String(),
- "Length": len(dest.withdrawList),
+ "Topic": "Table",
+ "Key": dest.GetNlri().String(),
}).Debug("Removing withdrawals")
// If we have some withdrawals and no know-paths, it means it is safe to
// delete these withdraws.
if len(dest.knownPathList) == 0 {
log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": dest.GetNlri().String(),
- "Length": len(dest.withdrawList),
+ "Topic": "Table",
+ "Key": dest.GetNlri().String(),
}).Debug("Found withdrawals for path(s) that did not get installed")
- dest.withdrawList = []*Path{}
return nil
}
- // If we have some known paths and some withdrawals, we find matches and
- // delete them first.
- matches := make([]*Path, 0, len(dest.withdrawList)/2)
- newKnownPaths := make([]*Path, 0, len(dest.knownPathList)/2)
-
// Match all withdrawals from destination paths.
- for _, withdraw := range dest.withdrawList {
- isFound := false
- for _, path := range dest.knownPathList {
- // We have a match if the source and path-id are same.
- if path.GetSource().Equal(withdraw.GetSource()) && path.GetNlri().PathIdentifier() == withdraw.GetNlri().PathIdentifier() {
- isFound = true
- // this path is referenced in peer's adj-rib-in
- // when there was no policy modification applied.
- // we could flag IsWithdraw down after use to avoid
- // a path with IsWithdraw flag exists in adj-rib-in
- path.IsWithdraw = true
- withdraw.GetNlri().SetPathLocalIdentifier(path.GetNlri().PathLocalIdentifier())
- matches = append(matches, withdraw)
- }
- }
-
- // We do no have any match for this withdraw.
- if !isFound {
- log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": dest.GetNlri().String(),
- "Path": withdraw,
- }).Warn("No matching path for withdraw found, may be path was not installed into table")
+ isFound := -1
+ for i, path := range dest.knownPathList {
+ // We have a match if the source and path-id are same.
+ if path.GetSource().Equal(withdraw.GetSource()) && path.GetNlri().PathIdentifier() == withdraw.GetNlri().PathIdentifier() {
+ isFound = i
+ withdraw.GetNlri().SetPathLocalIdentifier(path.GetNlri().PathLocalIdentifier())
}
}
- for _, path := range dest.knownPathList {
- if !path.IsWithdraw {
- newKnownPaths = append(newKnownPaths, path)
- }
- // here we flag IsWithdraw down
- path.IsWithdraw = false
+ // We do no have any match for this withdraw.
+ if isFound == -1 {
+ log.WithFields(log.Fields{
+ "Topic": "Table",
+ "Key": dest.GetNlri().String(),
+ "Path": withdraw,
+ }).Warn("No matching path for withdraw found, may be path was not installed into table")
+ return nil
+ } else {
+ p := dest.knownPathList[isFound]
+ dest.knownPathList = append(dest.knownPathList[:isFound], dest.knownPathList[isFound+1:]...)
+ return p
}
-
- dest.knownPathList = newKnownPaths
- dest.withdrawList = make([]*Path, 0)
- return matches
}
// Identifies which of known paths are old and removes them.
//
// Known paths will no longer have paths whose new version is present in
// new paths.
-func (dest *Destination) implicitWithdraw() paths {
- newKnownPaths := make([]*Path, 0, len(dest.knownPathList))
- implicitWithdrawn := make([]*Path, 0, len(dest.knownPathList))
- for _, path := range dest.knownPathList {
- found := false
- for _, newPath := range dest.newPathList {
- if newPath.NoImplicitWithdraw() {
- continue
- }
- // Here we just check if source is same and not check if path
- // version num. as newPaths are implicit withdrawal of old
- // paths and when doing RouteRefresh (not EnhancedRouteRefresh)
- // we get same paths again.
- if newPath.GetSource().Equal(path.GetSource()) && newPath.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() {
- log.WithFields(log.Fields{
- "Topic": "Table",
- "Key": dest.GetNlri().String(),
- "Path": path,
- }).Debug("Implicit withdrawal of old path, since we have learned new path from the same peer")
-
- found = true
- newPath.GetNlri().SetPathLocalIdentifier(path.GetNlri().PathLocalIdentifier())
- break
- }
+func (dest *Destination) implicitWithdraw(newPath *Path) {
+ found := -1
+ for i, path := range dest.knownPathList {
+ if newPath.NoImplicitWithdraw() {
+ continue
}
- if found {
- implicitWithdrawn = append(implicitWithdrawn, path)
- } else {
- newKnownPaths = append(newKnownPaths, path)
+ // Here we just check if source is same and not check if path
+ // version num. as newPaths are implicit withdrawal of old
+ // paths and when doing RouteRefresh (not EnhancedRouteRefresh)
+ // we get same paths again.
+ if newPath.GetSource().Equal(path.GetSource()) && newPath.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() {
+ log.WithFields(log.Fields{
+ "Topic": "Table",
+ "Key": dest.GetNlri().String(),
+ "Path": path,
+ }).Debug("Implicit withdrawal of old path, since we have learned new path from the same peer")
+
+ found = i
+ newPath.GetNlri().SetPathLocalIdentifier(path.GetNlri().PathLocalIdentifier())
+ break
}
}
- dest.knownPathList = newKnownPaths
- return implicitWithdrawn
+ if found != -1 {
+ dest.knownPathList = append(dest.knownPathList[:found], dest.knownPathList[found+1:]...)
+ }
}
func (dest *Destination) computeKnownBestPath() (*Path, BestPathReason, error) {
diff --git a/table/destination_test.go b/table/destination_test.go
index f488d4ac..0934057a 100644
--- a/table/destination_test.go
+++ b/table/destination_test.go
@@ -82,8 +82,7 @@ func TestCalculate2(t *testing.T) {
path1 := ProcessMessage(update1, peer1, time.Now())[0]
d := NewDestination(nlri, 0)
- d.AddNewPath(path1)
- d.Calculate()
+ d.Calculate(path1)
// suppose peer2 sends grammaatically correct but semantically flawed update message
// which has a withdrawal nlri not advertised before
@@ -92,8 +91,7 @@ func TestCalculate2(t *testing.T) {
path2 := ProcessMessage(update2, peer2, time.Now())[0]
assert.Equal(t, path2.IsWithdraw, true)
- d.AddWithdraw(path2)
- d.Calculate()
+ d.Calculate(path2)
// we have a path from peer1 here
assert.Equal(t, len(d.knownPathList), 1)
@@ -103,8 +101,7 @@ func TestCalculate2(t *testing.T) {
path3 := ProcessMessage(update3, peer2, time.Now())[0]
assert.Equal(t, path3.IsWithdraw, false)
- d.AddNewPath(path3)
- d.Calculate()
+ d.Calculate(path3)
// this time, we have paths from peer1 and peer2
assert.Equal(t, len(d.knownPathList), 2)
@@ -114,8 +111,7 @@ func TestCalculate2(t *testing.T) {
update4 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri})
path4 := ProcessMessage(update4, peer3, time.Now())[0]
- d.AddNewPath(path4)
- d.Calculate()
+ d.Calculate(path4)
// we must have paths from peer1, peer2 and peer3
assert.Equal(t, len(d.knownPathList), 3)
@@ -193,10 +189,8 @@ func TestTimeTieBreaker(t *testing.T) {
path2 := ProcessMessage(updateMsg, peer2, time.Now().Add(-1*time.Hour))[0] // older than path1
d := NewDestination(nlri, 0)
- d.AddNewPath(path1)
- d.AddNewPath(path2)
-
- d.Calculate()
+ 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
@@ -204,10 +198,8 @@ func TestTimeTieBreaker(t *testing.T) {
// this option disables tie breaking by age
SelectionOptions.ExternalCompareRouterId = true
d = NewDestination(nlri, 0)
- d.AddNewPath(path1)
- d.AddNewPath(path2)
-
- d.Calculate()
+ 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
@@ -361,18 +353,16 @@ func TestMultipath(t *testing.T) {
path2 := ProcessMessage(updateMsg, peer2, time.Now())[0]
d := NewDestination(nlri[0], 0)
- d.AddNewPath(path1)
- d.AddNewPath(path2)
+ d.Calculate(path2)
- best, old, multi := d.Calculate().GetChanges(GLOBAL_RIB_NAME, 0, false)
+ best, old, multi := d.Calculate(path1).GetChanges(GLOBAL_RIB_NAME, 0, false)
assert.NotNil(t, best)
- assert.Equal(t, old, (*Path)(nil))
+ 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)
- d.AddWithdraw(path3)
- dd := d.Calculate()
+ dd := d.Calculate(path3)
best, old, multi = dd.GetChanges(GLOBAL_RIB_NAME, 0, false)
assert.Nil(t, best)
assert.Equal(t, old, path1)
@@ -390,9 +380,8 @@ func TestMultipath(t *testing.T) {
}
updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
path4 := ProcessMessage(updateMsg, peer3, time.Now())[0]
- d.AddNewPath(path4)
-
- best, _, multi = d.Calculate().GetChanges(GLOBAL_RIB_NAME, 0, false)
+ 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)
@@ -406,9 +395,7 @@ func TestMultipath(t *testing.T) {
}
updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri)
path5 := ProcessMessage(updateMsg, peer2, time.Now())[0]
- d.AddNewPath(path5)
-
- best, _, multi = d.Calculate().GetChanges(GLOBAL_RIB_NAME, 0, false)
+ 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)
diff --git a/table/table.go b/table/table.go
index 6662376e..6bc88149 100644
--- a/table/table.go
+++ b/table/table.go
@@ -69,37 +69,6 @@ func (t *Table) GetRoutefamily() bgp.RouteFamily {
return t.routeFamily
}
-func (t *Table) insert(path *Path) *Destination {
- t.validatePath(path)
- dest := t.getOrCreateDest(path.GetNlri())
-
- if path.IsWithdraw {
- // withdraw insert
- dest.AddWithdraw(path)
- } else {
- // path insert
- dest.AddNewPath(path)
- }
- return dest
-}
-
-func (t *Table) DeleteDestByPeer(peerInfo *PeerInfo) []*Destination {
- dsts := []*Destination{}
- for _, dst := range t.destinations {
- match := false
- for _, p := range dst.knownPathList {
- if p.GetSource().Equal(peerInfo) {
- dst.AddWithdraw(p)
- match = true
- }
- }
- if match {
- dsts = append(dsts, dst)
- }
- }
- return dsts
-}
-
func (t *Table) deletePathsByVrf(vrf *Vrf) []*Path {
pathList := make([]*Path, 0)
for _, dest := range t.destinations {
diff --git a/table/table_manager.go b/table/table_manager.go
index 0e980404..e1accda7 100644
--- a/table/table_manager.go
+++ b/table/table_manager.go
@@ -180,65 +180,50 @@ func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) {
return msgs, nil
}
-func (manager *TableManager) calculate(dsts []*Destination) []*Destination {
- emptyDsts := make([]*Destination, 0, len(dsts))
- clonedDsts := make([]*Destination, 0, len(dsts))
-
- for _, dst := range dsts {
- log.WithFields(log.Fields{
- "Topic": "table",
- "Key": dst.GetNlri().String(),
- }).Debug("Processing destination")
-
- clonedDsts = append(clonedDsts, dst.Calculate())
-
- if len(dst.knownPathList) == 0 {
- emptyDsts = append(emptyDsts, dst)
- }
- }
-
- for _, dst := range emptyDsts {
- t := manager.Tables[dst.Family()]
+func (tm *TableManager) update(newPath *Path) *Destination {
+ t := tm.Tables[newPath.GetRouteFamily()]
+ t.validatePath(newPath)
+ dst := t.getOrCreateDest(newPath.GetNlri())
+ d := dst.Calculate(newPath)
+ if len(dst.knownPathList) == 0 {
t.deleteDest(dst)
}
- return clonedDsts
+ return d
}
-func (manager *TableManager) DeletePathsByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Destination {
+func (manager *TableManager) GetPathListByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Path {
if t, ok := manager.Tables[rf]; ok {
- dsts := t.DeleteDestByPeer(info)
- return manager.calculate(dsts)
+ pathList := make([]*Path, 0, len(t.destinations))
+ for _, dst := range t.destinations {
+ for _, p := range dst.knownPathList {
+ if p.GetSource().Equal(info) {
+ pathList = append(pathList, p)
+ }
+ }
+ }
+ return pathList
}
return nil
}
-func (manager *TableManager) ProcessPaths(pathList []*Path) []*Destination {
- m := make(map[string]bool, len(pathList))
- dsts := make([]*Destination, 0, len(pathList))
- for _, path := range pathList {
- if path == nil || path.IsEOR() {
- continue
- }
- rf := path.GetRouteFamily()
- if t, ok := manager.Tables[rf]; ok {
- dst := t.insert(path)
- key := dst.GetNlri().String()
- if !m[key] {
- m[key] = true
- dsts = append(dsts, dst)
- }
- if rf == bgp.RF_EVPN {
- for _, dst := range manager.handleMacMobility(path) {
- key := dst.GetNlri().String()
- if !m[key] {
- m[key] = true
- dsts = append(dsts, dst)
- }
- }
+func (manager *TableManager) Update(newPath *Path) []*Destination {
+ if newPath == nil || newPath.IsEOR() {
+ return nil
+ }
+
+ // normally, we'll have one destination.
+ dsts := make([]*Destination, 0, 1)
+ family := newPath.GetRouteFamily()
+ if _, ok := manager.Tables[family]; ok {
+ dsts = append(dsts, manager.update(newPath))
+
+ if family == bgp.RF_EVPN {
+ for _, p := range manager.handleMacMobility(newPath) {
+ dsts = append(dsts, manager.update(p))
}
}
}
- return manager.calculate(dsts)
+ return dsts
}
// EVPN MAC MOBILITY HANDLING
@@ -249,8 +234,8 @@ func (manager *TableManager) ProcessPaths(pathList []*Path) []*Destination {
// different Ethernet segment identifier and a higher sequence number
// than that which it had previously advertised withdraws its MAC/IP
// Advertisement route.
-func (manager *TableManager) handleMacMobility(path *Path) []*Destination {
- dsts := make([]*Destination, 0)
+func (manager *TableManager) handleMacMobility(path *Path) []*Path {
+ pathList := make([]*Path, 0)
nlri := path.GetNlri().(*bgp.EVPNNLRI)
if path.IsWithdraw || path.IsLocal() || nlri.RouteType != bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT {
return nil
@@ -275,12 +260,10 @@ func (manager *TableManager) handleMacMobility(path *Path) []*Destination {
e1, m1, s1 := f(path)
e2, m2, s2 := f(path2)
if bytes.Equal(m1, m2) && !bytes.Equal(e1.Value, e2.Value) && s1 > s2 {
- path2.IsWithdraw = true
- dsts = append(dsts, manager.Tables[bgp.RF_EVPN].insert(path2))
- break
+ pathList = append(pathList, path2.Clone(true))
}
}
- return dsts
+ return pathList
}
func (manager *TableManager) tables(list ...bgp.RouteFamily) []*Table {
diff --git a/table/table_manager_test.go b/table/table_manager_test.go
index 3e2d1e74..3c07dd53 100644
--- a/table/table_manager_test.go
+++ b/table/table_manager_test.go
@@ -31,7 +31,11 @@ import (
// this function processes only BGPUpdate
func (manager *TableManager) ProcessUpdate(fromPeer *PeerInfo, message *bgp.BGPMessage) ([]*Path, error) {
pathList := make([]*Path, 0)
- for _, d := range manager.ProcessPaths(ProcessMessage(message, fromPeer, time.Now())) {
+ dsts := make([]*Destination, 0)
+ for _, path := range ProcessMessage(message, fromPeer, time.Now()) {
+ dsts = append(dsts, manager.Update(path)...)
+ }
+ for _, d := range dsts {
b, _, _ := d.GetChanges(GLOBAL_RIB_NAME, 0, false)
pathList = append(pathList, b)
}