Skip to content
Snippets Groups Projects
Unverified Commit feb8f3fa authored by Daniel Czerwonk's avatar Daniel Czerwonk Committed by GitHub
Browse files

Merge pull request #13 from bio-routing/addpath

Adding BGP Path ID management
parents 127156f3 5fc3dabf
No related branches found
No related tags found
No related merge requests found
......@@ -12,16 +12,18 @@ import (
// AdjRIBOutAddPath represents an Adjacency RIB Out with BGP add path
type AdjRIBOutAddPath struct {
routingtable.ClientManager
rt *routingtable.RoutingTable
neighbor *routingtable.Neighbor
mu sync.RWMutex
rt *routingtable.RoutingTable
neighbor *routingtable.Neighbor
pathIDManager *pathIDManager
mu sync.RWMutex
}
// New creates a new Adjacency RIB Out with BGP add path
func New(neighbor *routingtable.Neighbor) *AdjRIBOutAddPath {
a := &AdjRIBOutAddPath{
rt: routingtable.NewRoutingTable(),
neighbor: neighbor,
rt: routingtable.NewRoutingTable(),
neighbor: neighbor,
pathIDManager: newPathIDManager(),
}
a.ClientManager = routingtable.NewClientManager(a)
return a
......@@ -41,8 +43,12 @@ func (a *AdjRIBOutAddPath) AddPath(pfx net.Prefix, p *route.Path) error {
a.mu.Lock()
defer a.mu.Unlock()
p.BGPPath.PathIdentifier = 7
pathID, err := a.pathIDManager.getNewID()
if err != nil {
return fmt.Errorf("Unable to get path ID: %v", err)
}
p.BGPPath.PathIdentifier = pathID
a.rt.AddPath(pfx, p)
for _, client := range a.ClientManager.Clients() {
......@@ -66,6 +72,7 @@ func (a *AdjRIBOutAddPath) RemovePath(pfx net.Prefix, p *route.Path) bool {
}
a.rt.RemovePath(pfx, p)
a.pathIDManager.releaseID(p.BGPPath.PathIdentifier)
a.removePathFromClients(pfx, p)
return true
}
......
package adjRIBOutAddPath
import (
"fmt"
)
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
}
func newPathIDManager() *pathIDManager {
return &pathIDManager{
ids: make(map[uint32]struct{}),
}
}
func (fm *pathIDManager) getNewID() (uint32, error) {
if fm.used == maxUint32 {
return 0, fmt.Errorf("Out of path IDs")
}
fm.last++
for {
if _, exists := fm.ids[fm.last]; exists {
fm.last++
continue
}
break
}
ret := fm.last
fm.used++
return ret, nil
}
func (fm *pathIDManager) releaseID(id uint32) {
if _, exists := fm.ids[id]; exists {
delete(fm.ids, id)
fm.used--
}
}
package adjRIBOutAddPath
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetNewID(t *testing.T) {
tests := []struct {
name string
maxIDs uint32
count int
wantFail bool
}{
{
name: "Out of path IDs",
maxIDs: 10,
count: 11,
wantFail: true,
},
{
name: "Success",
maxIDs: 10,
count: 10,
wantFail: false,
},
}
X:
for _, test := range tests {
maxUint32 = test.maxIDs
m := newPathIDManager()
for i := 0; i < test.count; i++ {
_, err := m.getNewID()
if err != nil {
if test.wantFail {
continue X
}
t.Errorf("Unexpected failure for test %q: %v", test.name, err)
continue X
}
}
if test.wantFail {
t.Errorf("Unexpected success for test %q", test.name)
continue
}
}
}
func TestReleaseID(t *testing.T) {
tests := []struct {
name string
pm *pathIDManager
release uint32
expected *pathIDManager
}{
{
name: "Release existent",
pm: &pathIDManager{
ids: map[uint32]struct{}{
0: struct{}{},
1: struct{}{},
2: struct{}{},
},
last: 2,
used: 3,
},
release: 1,
expected: &pathIDManager{
ids: map[uint32]struct{}{
0: struct{}{},
2: struct{}{},
},
last: 2,
used: 2,
},
},
{
name: "Release non-existent",
pm: &pathIDManager{
ids: map[uint32]struct{}{
0: struct{}{},
1: struct{}{},
2: struct{}{},
},
last: 2,
used: 3,
},
release: 3,
expected: &pathIDManager{
ids: map[uint32]struct{}{
0: struct{}{},
1: struct{}{},
2: struct{}{},
},
last: 2,
used: 3,
},
},
}
for _, test := range tests {
test.pm.releaseID(test.release)
assert.Equalf(t, test.expected, test.pm, "%s", test.name)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment