From 9279432c9167f647882f729f419dc3cfbf4ef7c1 Mon Sep 17 00:00:00 2001
From: Oliver Herms <oliver.herms@exaring.de>
Date: Wed, 20 Jun 2018 14:44:21 +0200
Subject: [PATCH] Making filters usable

---
 config/peer.go                          |  3 +++
 main.go                                 |  7 ++++-
 protocols/bgp/server/fsm_established.go |  7 +++--
 protocols/bgp/server/peer.go            | 10 ++++++++
 routingtable/filter/helper.go           | 29 +++++++++++++++++++++
 routingtable/filter/helper_test.go      | 34 +++++++++++++++++++++++++
 routingtable/filter/term.go             |  2 +-
 routingtable/filter/term_condition.go   | 12 +++++++++
 routingtable/filter/term_test.go        | 30 +++++++---------------
 9 files changed, 109 insertions(+), 25 deletions(-)
 create mode 100644 routingtable/filter/helper.go
 create mode 100644 routingtable/filter/helper_test.go

diff --git a/config/peer.go b/config/peer.go
index 245c1aa2..418d8e00 100644
--- a/config/peer.go
+++ b/config/peer.go
@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/bio-routing/bio-rd/routingtable/filter"
 )
 
 type Peer struct {
@@ -20,4 +21,6 @@ type Peer struct {
 	RouterID          uint32
 	AddPathSend       routingtable.ClientOptions
 	AddPathRecv       bool
+	ImportFilter      *filter.Filter
+	ExportFilter      *filter.Filter
 }
diff --git a/main.go b/main.go
index 49d19c0f..f74f4a0d 100644
--- a/main.go
+++ b/main.go
@@ -11,6 +11,7 @@ import (
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/server"
 	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/bio-routing/bio-rd/routingtable/filter"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 )
 
@@ -45,6 +46,8 @@ func main() {
 		AddPathSend: routingtable.ClientOptions{
 			MaxPaths: 10,
 		},
+		ExportFilter: filter.NewAcceptAllFilter(),
+		ImportFilter: filter.NewDrainFilter(),
 	}, rib)
 
 	//time.Sleep(time.Second * 15)
@@ -63,7 +66,9 @@ func main() {
 		AddPathSend: routingtable.ClientOptions{
 			MaxPaths: 10,
 		},
-		AddPathRecv: true,
+		AddPathRecv:  true,
+		ImportFilter: filter.NewDrainFilter(),
+		ExportFilter: filter.NewAcceptAllFilter(),
 	}, rib)
 
 	go func() {
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index 87ef4ba1..e54e6453 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -53,7 +53,9 @@ func (s establishedState) run() (state, string) {
 
 func (s *establishedState) init() {
 	s.fsm.adjRIBIn = adjRIBIn.New()
-	s.fsm.adjRIBIn.Register(s.fsm.rib)
+
+	s.fsm.peer.importFilter.Register(s.fsm.rib)
+	s.fsm.adjRIBIn.Register(s.fsm.peer.importFilter)
 
 	n := &routingtable.Neighbor{
 		Type:    route.BGPPathType,
@@ -71,7 +73,8 @@ func (s *establishedState) init() {
 	}
 
 	s.fsm.adjRIBOut.Register(s.fsm.updateSender)
-	s.fsm.rib.RegisterWithOptions(s.fsm.adjRIBOut, clientOptions)
+	s.fsm.peer.exportFilter.Register(s.fsm.adjRIBOut)
+	s.fsm.rib.RegisterWithOptions(s.fsm.peer.exportFilter, clientOptions)
 
 	s.fsm.ribsInitialized = true
 }
diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go
index 26f183ce..a0e4c623 100644
--- a/protocols/bgp/server/peer.go
+++ b/protocols/bgp/server/peer.go
@@ -96,6 +96,8 @@ func NewPeer(c config.Peer, rib routingtable.RouteTableClient, server *BGPServer
 		keepaliveTime:     c.KeepAlive,
 		holdTime:          c.HoldTime,
 		optOpenParams:     make([]packet.OptParam, 0),
+		importFilter:      filterOrDefault(c.ImportFilter),
+		exportFilter:      filterOrDefault(c.ExportFilter),
 	}
 	p.fsms = append(p.fsms, NewActiveFSM2(p))
 
@@ -130,6 +132,14 @@ func NewPeer(c config.Peer, rib routingtable.RouteTableClient, server *BGPServer
 	return p, nil
 }
 
+func filterOrDefault(f *filter.Filter) *filter.Filter {
+	if f != nil {
+		return f
+	}
+
+	return filter.NewDrainFilter()
+}
+
 // GetAddr returns the IP address of the peer
 func (p *Peer) GetAddr() net.IP {
 	return p.addr
diff --git a/routingtable/filter/helper.go b/routingtable/filter/helper.go
new file mode 100644
index 00000000..17a7d737
--- /dev/null
+++ b/routingtable/filter/helper.go
@@ -0,0 +1,29 @@
+package filter
+
+import (
+	"github.com/bio-routing/bio-rd/routingtable/filter/actions"
+)
+
+// NewAcceptAllFilter returns a filter accepting any paths/prefixes
+func NewAcceptAllFilter() *Filter {
+	return NewFilter(
+		[]*Term{
+			NewTerm(
+				[]*TermCondition{},
+				[]FilterAction{
+					&actions.AcceptAction{},
+				}),
+		})
+}
+
+// NewDrainFilter returns a filter rejecting any paths/prefixes
+func NewDrainFilter() *Filter {
+	return NewFilter(
+		[]*Term{
+			NewTerm(
+				[]*TermCondition{},
+				[]FilterAction{
+					&actions.RejectAction{},
+				}),
+		})
+}
diff --git a/routingtable/filter/helper_test.go b/routingtable/filter/helper_test.go
new file mode 100644
index 00000000..a0370e76
--- /dev/null
+++ b/routingtable/filter/helper_test.go
@@ -0,0 +1,34 @@
+package filter
+
+import (
+	"testing"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+)
+
+func TestNewAcceptAllFilter(t *testing.T) {
+	f := NewAcceptAllFilter()
+
+	m := &clientMock{}
+	f.Register(m)
+
+	f.AddPath(net.NewPfx(0, 0), &route.Path{})
+
+	if !m.addPathCalled {
+		t.Fatalf("expected accepted, but was filtered")
+	}
+}
+
+func TestNewDrainFilter(t *testing.T) {
+	f := NewDrainFilter()
+
+	m := &clientMock{}
+	f.Register(m)
+
+	f.AddPath(net.NewPfx(0, 0), &route.Path{})
+
+	if m.addPathCalled {
+		t.Fatalf("expected filtered, but was accepted")
+	}
+}
diff --git a/routingtable/filter/term.go b/routingtable/filter/term.go
index 0d546be8..d644acba 100644
--- a/routingtable/filter/term.go
+++ b/routingtable/filter/term.go
@@ -39,7 +39,7 @@ func (t *Term) Process(p net.Prefix, pa *route.Path) (modPath *route.Path, rejec
 		}
 	}
 
-	return orig, true
+	return orig, false
 }
 
 func (t *Term) processActions(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
diff --git a/routingtable/filter/term_condition.go b/routingtable/filter/term_condition.go
index fe19e461..9839ebe6 100644
--- a/routingtable/filter/term_condition.go
+++ b/routingtable/filter/term_condition.go
@@ -19,6 +19,18 @@ func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *T
 	}
 }
 
+func NewTermConditionWithRouteFilters(filters ...*RouteFilter) *TermCondition {
+	return &TermCondition{
+		routeFilters: filters,
+	}
+}
+
+func NewTermConditionWithPrefixLists(filters ...*PrefixList) *TermCondition {
+	return &TermCondition{
+		prefixLists: filters,
+	}
+}
+
 func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool {
 	return f.matchesPrefixListFilters(p) &&
 		f.machtchesRouteFilters(p) &&
diff --git a/routingtable/filter/term_test.go b/routingtable/filter/term_test.go
index 967480e7..d3abef87 100644
--- a/routingtable/filter/term_test.go
+++ b/routingtable/filter/term_test.go
@@ -45,11 +45,8 @@ func TestProcess(t *testing.T) {
 			prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
 			path:   &route.Path{},
 			from: []*TermCondition{
-				{
-					prefixLists: []*PrefixList{
-						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
-					},
-				},
+				NewTermConditionWithPrefixLists(
+					NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8))),
 			},
 			then: []FilterAction{
 				&actions.AcceptAction{},
@@ -62,16 +59,13 @@ func TestProcess(t *testing.T) {
 			prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
 			path:   &route.Path{},
 			from: []*TermCondition{
-				{
-					prefixLists: []*PrefixList{
-						NewPrefixList(net.NewPfx(0, 32)),
-					},
-				},
+				NewTermConditionWithPrefixLists(
+					NewPrefixList(net.NewPfx(0, 32))),
 			},
 			then: []FilterAction{
 				&actions.AcceptAction{},
 			},
-			expectReject:   true,
+			expectReject:   false,
 			expectModified: false,
 		},
 		{
@@ -79,11 +73,8 @@ func TestProcess(t *testing.T) {
 			prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
 			path:   &route.Path{},
 			from: []*TermCondition{
-				{
-					prefixLists: []*PrefixList{
-						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
-					},
-				},
+				NewTermConditionWithPrefixLists(
+					NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8))),
 			},
 			then: []FilterAction{
 				&mockAction{},
@@ -96,11 +87,8 @@ func TestProcess(t *testing.T) {
 			prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
 			path:   &route.Path{},
 			from: []*TermCondition{
-				{
-					prefixLists: []*PrefixList{
-						NewPrefixList(net.NewPfx(strAddr("100.64.0.1"), 8)),
-					},
-				},
+				NewTermConditionWithRouteFilters(
+					NewRouteFilter(net.NewPfx(strAddr("100.64.0.1"), 8), Exact())),
 			},
 			then: []FilterAction{
 				&mockAction{},
-- 
GitLab