diff --git a/AUTHORS b/AUTHORS index 4ac8c4a5ef9686bc11e6dfe3bfb04b8c633b6d53..e5550af433c7e0a9484e2dcc6864dfd4c143e3db 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,3 +13,4 @@ Cedric Kienzler Daniel Czerwonk Oliver Herms +Christoph Petrausch diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 0a06a59516ce817e9f1bb7e90a9d65a28df590c1..fcfb3b8f82816f64cc48ba60b973fad370be3f6a 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 ef2e881798212232fc6e116d2df2764e7d6207d3..6cfaf993303e727ddad5484c23683dc893f1d2ff 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 80ecb2f518c8ee7191ae570ad1455322a52ffe6b..300f5dcb96c07453cbee03c964935dad028a10da 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 86ff434675c2922f2f5c73803e4801c400751b60..aece08b7e592a2d4fd6119ba3562e5d15cbf5553 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 dd06e10069108809feb7da2118188a0fbe1bb4a9..b5c0b522ac4866cedba8de80213afa3564758905 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 0000000000000000000000000000000000000000..6493991c9c30a4df8352b4496f3fd953ad60a926 --- /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) + } +}