Skip to content
Snippets Groups Projects
Commit 9b5df52a authored by Daniel Czerwonk's avatar Daniel Czerwonk
Browse files

added basic filter structure

parent af41a165
No related branches found
No related tags found
No related merge requests found
package actions
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
)
type AcceptAction struct {
}
func (*AcceptAction) Do(p net.Prefix, pa *route.Path) (bool, *route.Path) {
return true, pa
}
package actions
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
)
type RejectAction struct {
}
func (*RejectAction) Do(p net.Prefix, pa *route.Path) (bool, *route.Path) {
return false, pa
}
package filter
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/bio-routing/bio-rd/routingtable"
)
type Filter struct {
routingtable.ClientManager
terms []*Term
}
func NewFilter(terms []*Term) *Filter {
f := &Filter{
terms: terms,
}
f.ClientManager = routingtable.NewClientManager(f)
return f
}
func (f *Filter) AddPath(p net.Prefix, pa *route.Path) error {
pa, rejected := f.processTerms(p, pa)
if rejected {
return nil
}
for _, c := range f.Clients() {
c.AddPath(p, pa)
}
return nil
}
func (f *Filter) RemovePath(p net.Prefix, pa *route.Path) bool {
pa, rejected := f.processTerms(p, pa)
if rejected {
return false
}
for _, c := range f.Clients() {
c.RemovePath(p, pa)
}
return true
}
func (f *Filter) UpdateNewClient(c routingtable.RouteTableClient) error {
return nil
}
func (f *Filter) processTerms(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
modPath = pa
for _, t := range f.terms {
modPath, reject = t.Process(p, modPath)
if reject {
return modPath, true
}
}
return modPath, false
}
package filter
import (
"testing"
"github.com/bio-routing/bio-rd/routingtable/filter/actions"
"github.com/stretchr/testify/assert"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/bio-routing/bio-rd/routingtable"
)
type clientMock struct {
routingtable.ClientManager
addPathCalled bool
removePathCalled bool
path *route.Path
}
func (m *clientMock) AddPath(p net.Prefix, pa *route.Path) error {
m.path = pa
m.addPathCalled = true
return nil
}
func (m *clientMock) RemovePath(p net.Prefix, pa *route.Path) bool {
m.path = pa
m.removePathCalled = true
return false
}
func (m *clientMock) UpdateNewClient(c routingtable.RouteTableClient) error {
return nil
}
func newClientMock() *clientMock {
m := &clientMock{}
m.ClientManager = routingtable.NewClientManager(m)
return m
}
func TestAddPath(t *testing.T) {
tests := []struct {
name string
prefix net.Prefix
path *route.Path
term *Term
exptectCalled bool
expectModified bool
}{
{
name: "accept",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&actions.AcceptAction{},
},
},
exptectCalled: true,
expectModified: false,
},
{
name: "reject",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&actions.RejectAction{},
},
},
exptectCalled: false,
expectModified: false,
},
{
name: "modified",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&mockAction{},
&actions.AcceptAction{},
},
},
exptectCalled: true,
expectModified: true,
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
m := newClientMock()
f := NewFilter([]*Term{test.term})
f.Register(m)
f.AddPath(test.prefix, test.path)
assert.Equal(te, test.exptectCalled, m.addPathCalled, "called")
if !test.exptectCalled {
return
}
if m.path != test.path && !test.expectModified {
te.Fatal("expected path to be not modified but was")
}
if m.path == test.path && test.expectModified {
te.Fatal("expected path to be modified but was same reference")
}
})
}
}
func TestRemovePath(t *testing.T) {
tests := []struct {
name string
prefix net.Prefix
path *route.Path
term *Term
exptectCalled bool
expectModified bool
}{
{
name: "accept",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&actions.AcceptAction{},
},
},
exptectCalled: true,
expectModified: false,
},
{
name: "reject",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&actions.RejectAction{},
},
},
exptectCalled: false,
expectModified: false,
},
{
name: "modified",
prefix: net.NewPfx(0, 0),
path: &route.Path{},
term: &Term{
then: []Then{
&mockAction{},
&actions.AcceptAction{},
},
},
exptectCalled: true,
expectModified: true,
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
m := newClientMock()
f := NewFilter([]*Term{test.term})
f.Register(m)
f.RemovePath(test.prefix, test.path)
assert.Equal(te, test.exptectCalled, m.removePathCalled, "called")
if !test.exptectCalled {
return
}
if m.path != test.path && !test.expectModified {
te.Fatal("expected path to be not modified but was")
}
if m.path == test.path && test.expectModified {
te.Fatal("expected path to be modified but was same reference")
}
})
}
}
package filter
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
)
type From struct {
prefixList *PrefixList
}
func (f *From) Matches(p net.Prefix, pa *route.Path) bool {
return f.prefixList.Matches(p)
}
package filter
import "github.com/bio-routing/bio-rd/net"
type PrefixList struct {
allowed []net.Prefix
}
func (f *PrefixList) Matches(p net.Prefix) bool {
for _, a := range f.allowed {
if !a.Contains(p) {
return false
}
}
return true
}
package filter
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
)
// Term matches a path against a list of conditions and performs actions if it matches
type Term struct {
from []*From
then []Then
}
// NewTerm creates a new term
func NewTerm(from []*From, then []Then) *Term {
t := &Term{
from: from,
then: then,
}
return t
}
// Process processes a path returning if the path should be rejected and returns a possible modified version of the path
func (t *Term) Process(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
orig := pa
if len(t.from) == 0 {
return t.processActions(p, pa)
}
for _, f := range t.from {
if f.Matches(p, pa) {
return t.processActions(p, pa)
}
}
return orig, true
}
func (t *Term) processActions(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
var result bool
modPath = pa
for _, action := range t.then {
result, modPath = action.Do(p, modPath)
if !result {
reject = true
continue
}
}
return modPath, reject
}
package filter
import (
"testing"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/bio-routing/bio-rd/routingtable/filter/actions"
"github.com/stretchr/testify/assert"
)
type mockAction struct {
}
func (*mockAction) Do(p net.Prefix, pa *route.Path) (bool, *route.Path) {
cp := *pa
cp.Type = route.OSPFPathType
return true, &cp
}
func TestProcess(t *testing.T) {
tests := []struct {
name string
prefix net.Prefix
path *route.Path
from []*From
then []Then
expectReject bool
expectModified bool
}{
{
name: "empty from",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{},
then: []Then{
&actions.AcceptAction{},
},
expectReject: false,
expectModified: false,
},
{
name: "from matches",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 0),
},
},
},
},
then: []Then{
&actions.AcceptAction{},
},
expectReject: false,
expectModified: false,
},
{
name: "from does not match",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 32),
},
},
},
},
then: []Then{
&actions.AcceptAction{},
},
expectReject: true,
expectModified: false,
},
{
name: "modified",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 0),
},
},
},
},
then: []Then{
&mockAction{},
},
expectReject: false,
expectModified: true,
},
{
name: "modified and accepted (2 actions)",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 0),
},
},
},
},
then: []Then{
&mockAction{},
&actions.AcceptAction{},
},
expectReject: false,
expectModified: true,
},
{
name: "one of the prefix filters matches",
prefix: net.NewPfx(strAddr("100.64.0.1"), 8),
path: &route.Path{},
from: []*From{
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 32),
},
},
},
{
&PrefixList{
allowed: []net.Prefix{
net.NewPfx(0, 0),
},
},
},
},
then: []Then{
&actions.AcceptAction{},
},
expectReject: false,
expectModified: false,
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
term := NewTerm(test.from, test.then)
pa, reject := term.Process(test.prefix, test.path)
assert.Equal(te, test.expectReject, reject, "reject")
if pa != test.path && !test.expectModified {
te.Fatal("expected path to be not modified but was")
}
if pa == test.path && test.expectModified {
te.Fatal("expected path to be modified but was same reference")
}
})
}
}
func strAddr(s string) uint32 {
ret, _ := net.StrToAddr(s)
return ret
}
package filter
import (
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
)
type Then interface {
Do(p net.Prefix, pa *route.Path) (bool, *route.Path)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment