Skip to content
Snippets Groups Projects
Unverified Commit 044bfeb2 authored by takt's avatar takt Committed by GitHub
Browse files

Merge pull request #8 from bio-routing/feature/filters_poc

Feature/filters poc
parents 5f286792 8b5eac66
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) (modPath *route.Path, reject bool) {
return pa, false
}
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) (modPath *route.Path, reject bool) {
return pa, true
}
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) {
modPath = pa
for _, action := range t.then {
modPath, reject = action.Do(p, modPath)
if reject {
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) (*route.Path, bool) {
cp := *pa
cp.Type = route.OSPFPathType
return &cp, false
}
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) (modPath *route.Path, reject bool)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment