From 5dab1a2cf1a05b84ddd423e37df4f486ab81e80c Mon Sep 17 00:00:00 2001
From: Daniel Czerwonk <daniel@dan-nrw.de>
Date: Mon, 14 May 2018 15:14:24 +0200
Subject: [PATCH] prefix list now with matching strategy, next step in
 implementing terms

---
 routingtable/filter/from.go           |  15 +++-
 routingtable/filter/from_test.go      | 120 ++++++++++++++++++++++++++
 routingtable/filter/prefix_list.go    |  16 +++-
 routingtable/filter/prefix_matcher.go |  30 +++++++
 routingtable/filter/route_filter.go   |  27 ------
 routingtable/filter/term_test.go      |  20 ++---
 6 files changed, 186 insertions(+), 42 deletions(-)
 create mode 100644 routingtable/filter/from_test.go
 create mode 100644 routingtable/filter/prefix_matcher.go

diff --git a/routingtable/filter/from.go b/routingtable/filter/from.go
index 10825397..61212204 100644
--- a/routingtable/filter/from.go
+++ b/routingtable/filter/from.go
@@ -6,11 +6,12 @@ import (
 )
 
 type From struct {
-	prefixLists []*PrefixList
+	prefixLists  []*PrefixList
+	routeFilters []*RouteFilter
 }
 
 func (f *From) Matches(p net.Prefix, pa *route.Path) bool {
-	return f.matchesAnyPrefixList(p)
+	return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p)
 }
 
 func (t *From) matchesAnyPrefixList(p net.Prefix) bool {
@@ -22,3 +23,13 @@ func (t *From) matchesAnyPrefixList(p net.Prefix) bool {
 
 	return false
 }
+
+func (t *From) machtchesAnyRouteFilter(p net.Prefix) bool {
+	for _, l := range t.routeFilters {
+		if l.Matches(p) {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/routingtable/filter/from_test.go b/routingtable/filter/from_test.go
new file mode 100644
index 00000000..acffa60a
--- /dev/null
+++ b/routingtable/filter/from_test.go
@@ -0,0 +1,120 @@
+package filter
+
+import (
+	"testing"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMatches(t *testing.T) {
+	tests := []struct {
+		name         string
+		prefix       net.Prefix
+		prefixLists  []*PrefixList
+		routeFilters []*RouteFilter
+		expected     bool
+	}{
+		{
+			name:   "one prefix matches in prefix list, no route filters set",
+			prefix: net.NewPfx(strAddr("127.0.0.1"), 8),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)),
+			},
+			routeFilters: []*RouteFilter{},
+			expected:     true,
+		},
+		{
+			name:   "one prefix in prefix list and no match, no route filters set",
+			prefix: net.NewPfx(strAddr("127.0.0.1"), 8),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(0, 32)),
+			},
+			routeFilters: []*RouteFilter{},
+			expected:     false,
+		},
+		{
+			name:   "one prefix of 2 matches in prefix list, no route filters set",
+			prefix: net.NewPfx(strAddr("127.0.0.1"), 8),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(strAddr("10.0.0.0"), 8)),
+				NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)),
+			},
+			routeFilters: []*RouteFilter{},
+			expected:     true,
+		},
+		{
+			name:        "no prefixes in prefix list, only route filter matches",
+			prefix:      net.NewPfx(strAddr("10.0.0.0"), 24),
+			prefixLists: []*PrefixList{},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: true,
+		},
+		{
+			name:        "no prefixes in prefix list, one route filter matches",
+			prefix:      net.NewPfx(strAddr("10.0.0.0"), 24),
+			prefixLists: []*PrefixList{},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("8.0.0.0"), 8), Longer()),
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: true,
+		},
+		{
+			name:        "no prefixes in prefix list, one of many route filters matches",
+			prefix:      net.NewPfx(strAddr("127.0.0.1"), 8),
+			prefixLists: []*PrefixList{},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: false,
+		},
+		{
+			name:   "no match in prefix list, no macht in route filter",
+			prefix: net.NewPfx(strAddr("9.9.9.0"), 24),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)),
+			},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: false,
+		},
+		{
+			name:   "one prefix in prefixlist, one route fitler, only prefix list matches",
+			prefix: net.NewPfx(strAddr("8.8.8.0"), 24),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)),
+			},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: true,
+		},
+		{
+			name:   "one prefix in prefixlist, one route fitler, only route filter matches",
+			prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
+			prefixLists: []*PrefixList{
+				NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)),
+			},
+			routeFilters: []*RouteFilter{
+				NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
+			},
+			expected: true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			f := &From{
+				prefixLists:  test.prefixLists,
+				routeFilters: test.routeFilters,
+			}
+
+			assert.Equal(te, test.expected, f.Matches(test.prefix, &route.Path{}))
+		})
+	}
+}
diff --git a/routingtable/filter/prefix_list.go b/routingtable/filter/prefix_list.go
index 8ccf36e8..91668160 100644
--- a/routingtable/filter/prefix_list.go
+++ b/routingtable/filter/prefix_list.go
@@ -4,21 +4,31 @@ import "github.com/bio-routing/bio-rd/net"
 
 type PrefixList struct {
 	allowed []net.Prefix
+	matcher PrefixMatcher
 }
 
 func NewPrefixList(pfxs ...net.Prefix) *PrefixList {
 	l := &PrefixList{
 		allowed: pfxs,
+		matcher: Exact(),
+	}
+	return l
+}
+
+func NewPrefixListWithMatcher(matcher PrefixMatcher, pfxs ...net.Prefix) *PrefixList {
+	l := &PrefixList{
+		allowed: pfxs,
+		matcher: matcher,
 	}
 	return l
 }
 
 func (l *PrefixList) Matches(p net.Prefix) bool {
 	for _, a := range l.allowed {
-		if !a.Contains(p) {
-			return false
+		if a.Equal(p) {
+			return true
 		}
 	}
 
-	return true
+	return false
 }
diff --git a/routingtable/filter/prefix_matcher.go b/routingtable/filter/prefix_matcher.go
new file mode 100644
index 00000000..8b6136b5
--- /dev/null
+++ b/routingtable/filter/prefix_matcher.go
@@ -0,0 +1,30 @@
+package filter
+
+import "github.com/bio-routing/bio-rd/net"
+
+type PrefixMatcher func(pattern, prefix net.Prefix) bool
+
+func InRange(min, max uint8) PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		contains := pattern.Equal(prefix) || pattern.Contains(prefix)
+		return contains && prefix.Pfxlen() >= min && prefix.Pfxlen() <= max
+	}
+}
+
+func Exact() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Equal(prefix)
+	}
+}
+
+func OrLonger() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Equal(prefix) || pattern.Contains(prefix)
+	}
+}
+
+func Longer() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Contains(prefix) && prefix.Pfxlen() > pattern.Pfxlen()
+	}
+}
diff --git a/routingtable/filter/route_filter.go b/routingtable/filter/route_filter.go
index 78a922fe..d6716b51 100644
--- a/routingtable/filter/route_filter.go
+++ b/routingtable/filter/route_filter.go
@@ -9,33 +9,6 @@ type RouteFilter struct {
 	matcher PrefixMatcher
 }
 
-type PrefixMatcher func(pattern, prefix net.Prefix) bool
-
-func InRange(min, max uint8) PrefixMatcher {
-	return func(pattern, prefix net.Prefix) bool {
-		contains := pattern.Equal(prefix) || pattern.Contains(prefix)
-		return contains && prefix.Pfxlen() >= min && prefix.Pfxlen() <= max
-	}
-}
-
-func Exact() PrefixMatcher {
-	return func(pattern, prefix net.Prefix) bool {
-		return pattern.Equal(prefix)
-	}
-}
-
-func OrLonger() PrefixMatcher {
-	return func(pattern, prefix net.Prefix) bool {
-		return pattern.Equal(prefix) || pattern.Contains(prefix)
-	}
-}
-
-func Longer() PrefixMatcher {
-	return func(pattern, prefix net.Prefix) bool {
-		return pattern.Contains(prefix) && prefix.Pfxlen() > pattern.Pfxlen()
-	}
-}
-
 func NewRouteFilter(pattern net.Prefix, matcher PrefixMatcher) *RouteFilter {
 	return &RouteFilter{
 		pattern: pattern,
diff --git a/routingtable/filter/term_test.go b/routingtable/filter/term_test.go
index bf045323..9720dbe3 100644
--- a/routingtable/filter/term_test.go
+++ b/routingtable/filter/term_test.go
@@ -46,8 +46,8 @@ func TestProcess(t *testing.T) {
 			path:   &route.Path{},
 			from: []*From{
 				{
-					[]*PrefixList{
-						NewPrefixList(net.NewPfx(0, 0)),
+					prefixLists: []*PrefixList{
+						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
 					},
 				},
 			},
@@ -63,7 +63,7 @@ func TestProcess(t *testing.T) {
 			path:   &route.Path{},
 			from: []*From{
 				{
-					[]*PrefixList{
+					prefixLists: []*PrefixList{
 						NewPrefixList(net.NewPfx(0, 32)),
 					},
 				},
@@ -80,8 +80,8 @@ func TestProcess(t *testing.T) {
 			path:   &route.Path{},
 			from: []*From{
 				{
-					[]*PrefixList{
-						NewPrefixList(net.NewPfx(0, 0)),
+					prefixLists: []*PrefixList{
+						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
 					},
 				},
 			},
@@ -97,8 +97,8 @@ func TestProcess(t *testing.T) {
 			path:   &route.Path{},
 			from: []*From{
 				{
-					[]*PrefixList{
-						NewPrefixList(net.NewPfx(0, 0)),
+					prefixLists: []*PrefixList{
+						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
 					},
 				},
 			},
@@ -115,9 +115,9 @@ func TestProcess(t *testing.T) {
 			path:   &route.Path{},
 			from: []*From{
 				{
-					[]*PrefixList{
-						NewPrefixList(net.NewPfx(0, 32)),
-						NewPrefixList(net.NewPfx(0, 0)),
+					prefixLists: []*PrefixList{
+						NewPrefixListWithMatcher(Exact(), net.NewPfx(0, 32)),
+						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
 					},
 				},
 			},
-- 
GitLab