From bf0beb230ef17571f28ac04c38a1714472a470da Mon Sep 17 00:00:00 2001
From: Oliver Herms <oliver.herms@exaring.de>
Date: Sat, 23 Jun 2018 17:47:04 +0200
Subject: [PATCH] Fixed add path path IDs

---
 main.go                                       |  8 ++--
 protocols/bgp/server/{fsm2.go => fsm.go}      |  0
 protocols/bgp/server/update_helper.go         |  1 +
 route/bgp.go                                  |  4 ++
 ...adj_rib_out_add_path.go => adj_rib_out.go} | 18 +++++++-
 routingtable/adjRIBOut/path_id_manager.go     | 41 ++++++++++++++-----
 6 files changed, 55 insertions(+), 17 deletions(-)
 rename protocols/bgp/server/{fsm2.go => fsm.go} (100%)
 rename routingtable/adjRIBOut/{adj_rib_out_add_path.go => adj_rib_out.go} (89%)

diff --git a/main.go b/main.go
index c312e33c..e93abbee 100644
--- a/main.go
+++ b/main.go
@@ -41,7 +41,7 @@ func main() {
 
 	b.AddPeer(config.Peer{
 		AdminEnabled:      true,
-		LocalAS:           65200,
+		LocalAS:           6695,
 		PeerAS:            65300,
 		PeerAddress:       net.IP([]byte{169, 254, 200, 1}),
 		LocalAddress:      net.IP([]byte{169, 254, 200, 0}),
@@ -53,14 +53,14 @@ func main() {
 		AddPathSend: routingtable.ClientOptions{
 			MaxPaths: 10,
 		},
-		ImportFilter:      filter.NewDrainFilter(),
+		ImportFilter:      filter.NewAcceptAllFilter(),
 		ExportFilter:      filter.NewAcceptAllFilter(),
 		RouteServerClient: true,
 	}, rib)
 
 	b.AddPeer(config.Peer{
 		AdminEnabled:      true,
-		LocalAS:           65200,
+		LocalAS:           6695,
 		PeerAS:            65100,
 		PeerAddress:       net.IP([]byte{169, 254, 100, 0}),
 		LocalAddress:      net.IP([]byte{169, 254, 100, 1}),
@@ -74,7 +74,7 @@ func main() {
 		},
 		AddPathRecv:       true,
 		ImportFilter:      filter.NewAcceptAllFilter(),
-		ExportFilter:      filter.NewDrainFilter(),
+		ExportFilter:      filter.NewAcceptAllFilter(),
 		RouteServerClient: true,
 	}, rib)
 
diff --git a/protocols/bgp/server/fsm2.go b/protocols/bgp/server/fsm.go
similarity index 100%
rename from protocols/bgp/server/fsm2.go
rename to protocols/bgp/server/fsm.go
diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go
index e0a24a6e..34f784a1 100644
--- a/protocols/bgp/server/update_helper.go
+++ b/protocols/bgp/server/update_helper.go
@@ -82,6 +82,7 @@ func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate) error {
 		return nil
 	}
 
+	fmt.Printf("Sending Update: %v\n", updateBytes)
 	_, err = out.Write(updateBytes)
 	if err != nil {
 		return fmt.Errorf("Failed sending Update: %v", err)
diff --git a/route/bgp.go b/route/bgp.go
index d0eaf295..a63eb2fd 100644
--- a/route/bgp.go
+++ b/route/bgp.go
@@ -158,6 +158,10 @@ func (b *BGPPath) Print() string {
 	nh := uint32To4Byte(b.NextHop)
 	ret += fmt.Sprintf("\t\tNEXT HOP: %d.%d.%d.%d\n", nh[0], nh[1], nh[2], nh[3])
 	ret += fmt.Sprintf("\t\tMED: %d\n", b.MED)
+	ret += fmt.Sprintf("\t\tPath ID: %d\n", b.PathIdentifier)
+	ret += fmt.Sprintf("\t\tSource: %d\n", b.Source)
+	ret += fmt.Sprintf("\t\tCommunities: %s\n", b.Communities)
+	ret += fmt.Sprintf("\t\tLargeCommunities: %s\n", b.LargeCommunities)
 
 	return ret
 }
diff --git a/routingtable/adjRIBOut/adj_rib_out_add_path.go b/routingtable/adjRIBOut/adj_rib_out.go
similarity index 89%
rename from routingtable/adjRIBOut/adj_rib_out_add_path.go
rename to routingtable/adjRIBOut/adj_rib_out.go
index 44661441..e5ea8e51 100644
--- a/routingtable/adjRIBOut/adj_rib_out_add_path.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -67,10 +67,12 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 		a.removePathsFromClients(pfx, oldPaths)
 	}
 
-	pathID, err := a.pathIDManager.getNewID()
+	fmt.Printf("Adding path: %s\n", p.Print())
+	pathID, err := a.pathIDManager.addPath(p)
 	if err != nil {
 		return fmt.Errorf("Unable to get path ID: %v", err)
 	}
+	fmt.Printf("New path ID: %d\n", pathID)
 
 	p.BGPPath.PathIdentifier = pathID
 	a.rt.AddPath(pfx, p)
@@ -90,6 +92,11 @@ func (a *AdjRIBOut) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
 		return false
 	}
 
+	p, reject := a.exportFilter.ProcessTerms(pfx, p)
+	if reject {
+		return false
+	}
+
 	a.mu.Lock()
 	defer a.mu.Unlock()
 
@@ -99,7 +106,14 @@ func (a *AdjRIBOut) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
 	}
 
 	a.rt.RemovePath(pfx, p)
-	a.pathIDManager.releaseID(p.BGPPath.PathIdentifier)
+	pathID, err := a.pathIDManager.releasePath(p)
+	if err != nil {
+		log.Warningf("Unable to release path: %v", err)
+		return true
+	}
+
+	p = p.Copy()
+	p.BGPPath.PathIdentifier = pathID
 	a.removePathFromClients(pfx, p)
 	return true
 }
diff --git a/routingtable/adjRIBOut/path_id_manager.go b/routingtable/adjRIBOut/path_id_manager.go
index 53ab2a98..377ce9b3 100644
--- a/routingtable/adjRIBOut/path_id_manager.go
+++ b/routingtable/adjRIBOut/path_id_manager.go
@@ -2,24 +2,34 @@ package adjRIBOut
 
 import (
 	"fmt"
+
+	"github.com/bio-routing/bio-rd/route"
 )
 
 var maxUint32 = ^uint32(0)
 
 // pathIDManager manages BGP path identifiers for add-path. This is no thread safe (and doesn't need to be).
 type pathIDManager struct {
-	ids  map[uint32]struct{}
-	last uint32
-	used uint32
+	ids      map[uint32]uint64
+	idByPath map[route.BGPPath]uint32
+	last     uint32
+	used     uint32
 }
 
 func newPathIDManager() *pathIDManager {
 	return &pathIDManager{
-		ids: make(map[uint32]struct{}),
+		ids:      make(map[uint32]uint64),
+		idByPath: make(map[route.BGPPath]uint32),
 	}
 }
 
-func (fm *pathIDManager) getNewID() (uint32, error) {
+func (fm *pathIDManager) addPath(p *route.Path) (uint32, error) {
+	if _, exists := fm.idByPath[*p.BGPPath]; exists {
+		id := fm.idByPath[*p.BGPPath]
+		fm.ids[id]++
+		return id, nil
+	}
+
 	if fm.used == maxUint32 {
 		return 0, fmt.Errorf("Out of path IDs")
 	}
@@ -33,15 +43,24 @@ func (fm *pathIDManager) getNewID() (uint32, error) {
 		break
 	}
 
-	ret := fm.last
+	fm.idByPath[*p.BGPPath] = fm.last
+	fm.ids[fm.last] = 1
 	fm.used++
 
-	return ret, nil
+	return fm.last, nil
 }
 
-func (fm *pathIDManager) releaseID(id uint32) {
-	if _, exists := fm.ids[id]; exists {
-		delete(fm.ids, id)
-		fm.used--
+func (fm *pathIDManager) releasePath(p *route.Path) (uint32, error) {
+	if _, exists := fm.idByPath[*p.BGPPath]; !exists {
+		return 0, fmt.Errorf("ID not found for path: %s", p.Print())
 	}
+
+	id := fm.idByPath[*p.BGPPath]
+	fm.ids[id]--
+	if fm.ids[id] == 0 {
+		delete(fm.ids, fm.idByPath[*p.BGPPath])
+		delete(fm.idByPath, *p.BGPPath)
+	}
+
+	return id, nil
 }
-- 
GitLab