From 6c91410c5bc1530430aa29e55cbc15d31bc62a9d Mon Sep 17 00:00:00 2001 From: Christoph Petrausch <263448+hikhvar@users.noreply.github.com> Date: Thu, 17 May 2018 15:58:21 +0200 Subject: [PATCH] Feature: Add function to check if localRIB contains a given path and prefix combination. (#11) * Add a ContainsPfxPath method to LocRIB to check if a route exists already. * Check for nil pathes in compare * Add myself to CONTRIBUTORS and AUTHORS * Added docs * Avoid segfault on nil and remove shaddowing of keyword new * Make route == nil useful * Update loc_rib.go --- AUTHORS | 1 + CONTRIBUTORS | 1 + route/path.go | 10 +++ route/route.go | 24 +++++-- route/route_test.go | 101 ++++++++++++++++++++++++++++ routingtable/locRIB/loc_rib.go | 20 ++++++ routingtable/locRIB/loc_rib_test.go | 86 +++++++++++++++++++++++ 7 files changed, 237 insertions(+), 6 deletions(-) create mode 100644 routingtable/locRIB/loc_rib_test.go diff --git a/AUTHORS b/AUTHORS index 4ac8c4a5..e5550af4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,3 +13,4 @@ Cedric Kienzler Daniel Czerwonk Oliver Herms +Christoph Petrausch diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0a06a595..fcfb3b8f 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -7,3 +7,4 @@ Cedric Kienzler Daniel Czerwonk Oliver Herms +Christoph Petrausch \ No newline at end of file diff --git a/route/path.go b/route/path.go index ef2e8817..6cfaf993 100644 --- a/route/path.go +++ b/route/path.go @@ -10,6 +10,16 @@ type Path struct { // Compare returns negative if p < q, 0 if paths are equal, positive if p > q func (p *Path) Compare(q *Path) int8 { + switch { + case p == nil && q == nil: + return 0 + case p == nil: + return -1 + case q == nil: + return 1 + default: + } + if p.Type > q.Type { return 1 } diff --git a/route/route.go b/route/route.go index 80ecb2f5..300f5dcb 100644 --- a/route/route.go +++ b/route/route.go @@ -45,13 +45,16 @@ func NewRoute(pfx net.Prefix, p *Path) *Route { // Copy returns a copy of route r func (r *Route) Copy() *Route { - new := &Route{ + if r == nil { + return nil + } + n := &Route{ pfx: r.pfx, ecmpPaths: r.ecmpPaths, } - new.paths = make([]*Path, len(r.paths)) - copy(new.paths, r.paths) - return new + n.paths = make([]*Path, len(r.paths)) + copy(n.paths, r.paths) + return n } // Prefix gets the prefix of route `r` @@ -71,8 +74,8 @@ func (r *Route) Pfxlen() uint8 { // Paths returns a copy of the list of paths associated with route r func (r *Route) Paths() []*Path { - if r.paths == nil { - return []*Path{} + if r == nil || r.paths == nil { + return nil } ret := make([]*Path, len(r.paths)) @@ -82,11 +85,17 @@ func (r *Route) Paths() []*Path { // ECMPPathCount returns the count of ecmp paths for route r func (r *Route) ECMPPathCount() uint { + if r == nil { + return 0 + } return r.ecmpPaths } // ECMPPaths returns a copy of the list of paths associated with route r func (r *Route) ECMPPaths() []*Path { + if r == nil { + return nil + } r.mu.Lock() defer r.mu.Unlock() @@ -101,6 +110,9 @@ func (r *Route) ECMPPaths() []*Path { // BestPath returns the current best path. nil if non exists func (r *Route) BestPath() *Path { + if r == nil { + return nil + } if len(r.paths) == 0 { return nil } diff --git a/route/route_test.go b/route/route_test.go index 86ff4346..aece08b7 100644 --- a/route/route_test.go +++ b/route/route_test.go @@ -289,6 +289,9 @@ func TestCopy(t *testing.T) { }, }, }, + { + name: "", + }, } for _, test := range tests { @@ -297,6 +300,104 @@ func TestCopy(t *testing.T) { } } +func TestECMPPathCount(t *testing.T) { + var r *Route + assert.Equal(t, uint(0), r.ECMPPathCount()) + r = &Route{} + assert.Equal(t, uint(0), r.ECMPPathCount()) + r.ecmpPaths = 12 + assert.Equal(t, uint(12), r.ECMPPathCount()) +} + +func TestBestPath(t *testing.T) { + tests := []struct { + route *Route + expected *Path + }{ + { + route: nil, + expected: nil, + }, + { + route: &Route{}, + expected: nil, + }, + { + route: &Route{ + paths: []*Path{ + { + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + }, + }, + expected: &Path{ + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + }, + } + for _, tc := range tests { + assert.Equal(t, tc.expected, tc.route.BestPath()) + } +} + +func TestECMPPaths(t *testing.T) { + tests := []struct { + route *Route + expected []*Path + }{ + { + route: nil, + expected: nil, + }, + { + route: &Route{}, + expected: nil, + }, + { + route: &Route{ + ecmpPaths: 2, + paths: []*Path{ + { + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + { + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + }, + }, + expected: []*Path{ + { + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + { + Type: StaticPathType, + StaticPath: &StaticPath{ + NextHop: 32, + }, + }, + }, + }, + } + for _, tc := range tests { + assert.Equal(t, tc.expected, tc.route.ECMPPaths()) + } +} + func strAddr(s string) uint32 { ret, _ := net.StrToAddr(s) return ret diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go index dd06e100..b5c0b522 100644 --- a/routingtable/locRIB/loc_rib.go +++ b/routingtable/locRIB/loc_rib.go @@ -125,6 +125,26 @@ func (a *LocRIB) removePathsFromClients(oldRoute *route.Route, newRoute *route.R } } +// ContainsPfxPath returns true if this prefix and path combination is +// present in this LocRIB. +func (a *LocRIB) ContainsPfxPath(pfx net.Prefix, p *route.Path) bool { + a.mu.RLock() + defer a.mu.RUnlock() + + r := a.rt.Get(pfx) + if r == nil { + return false + } + + for _, path := range r.Paths() { + if path.Compare(p) == 0 { + return true + } + } + + return false +} + func (a *LocRIB) Print() string { a.mu.RLock() defer a.mu.RUnlock() diff --git a/routingtable/locRIB/loc_rib_test.go b/routingtable/locRIB/loc_rib_test.go new file mode 100644 index 00000000..6493991c --- /dev/null +++ b/routingtable/locRIB/loc_rib_test.go @@ -0,0 +1,86 @@ +package locRIB + +import ( + "testing" + + "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/route" + + "github.com/stretchr/testify/assert" +) + +type pfxPath struct { + pfx net.Prefix + path *route.Path +} + +type containsPfxPathTestcase struct { + in []pfxPath + check pfxPath + expected bool +} + +func TestContainsPfxPath(t *testing.T) { + testCases := []containsPfxPathTestcase{ + { + in: []pfxPath{}, + check: pfxPath{ + pfx: net.NewPfx(1, 32), + path: nil, + }, + expected: false, + }, + // Not equal path + { + in: []pfxPath{ + { + pfx: net.NewPfx(1, 32), + path: &route.Path{ + Type: route.StaticPathType, + StaticPath: &route.StaticPath{ + NextHop: 2, + }, + }, + }, + }, + check: pfxPath{ + pfx: net.NewPfx(1, 32), + path: nil, + }, + expected: false, + }, + // Equal + { + in: []pfxPath{ + { + pfx: net.NewPfx(1, 32), + path: &route.Path{ + Type: route.StaticPathType, + StaticPath: &route.StaticPath{ + NextHop: 2, + }, + }, + }, + }, + check: pfxPath{ + pfx: net.NewPfx(1, 32), + path: &route.Path{ + Type: route.StaticPathType, + StaticPath: &route.StaticPath{ + NextHop: 2, + }, + }, + }, + expected: true, + }, + } + for i, tc := range testCases { + rib := New() + for _, p := range tc.in { + err := rib.AddPath(p.pfx, p.path) + assert.Nil(t, err, "could not fill rib in testcase %v", i) + } + contains := rib.ContainsPfxPath(tc.check.pfx, tc.check.path) + assert.Equal(t, tc.expected, contains, "mismatch in testcase %v", i) + } +} -- GitLab