diff --git a/routingtable/filter/BUILD.bazel b/routingtable/filter/BUILD.bazel index 4ac13572ad6e4ec9364449e209fa641a2f7c8125..17bee85a8312740e989ae1f88fcf0150458437fa 100644 --- a/routingtable/filter/BUILD.bazel +++ b/routingtable/filter/BUILD.bazel @@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "action.go", "community_filter.go", "filter.go", "helper.go", diff --git a/routingtable/filter/action.go b/routingtable/filter/action.go new file mode 100644 index 0000000000000000000000000000000000000000..888ad3f5397f51337cfb04b487883956da107f80 --- /dev/null +++ b/routingtable/filter/action.go @@ -0,0 +1,12 @@ +package filter + +import ( + "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/route" + "github.com/bio-routing/bio-rd/routingtable/filter/actions" +) + +// Action performs actions on a `route.Path` +type Action interface { + Do(p net.Prefix, pa *route.Path) actions.Result +} diff --git a/routingtable/filter/actions/BUILD.bazel b/routingtable/filter/actions/BUILD.bazel index b4195842fcc40a6d484111cb9aed065d02e1b604..d974ffd1c11bf232f50458e3a5c3a96ed8a08fbd 100644 --- a/routingtable/filter/actions/BUILD.bazel +++ b/routingtable/filter/actions/BUILD.bazel @@ -4,10 +4,10 @@ go_library( name = "go_default_library", srcs = [ "accept_action.go", + "action.go", "add_community_action.go", "add_large_community_action.go", "as_path_prepend_action.go", - "filter_action.go", "reject_action.go", "set_local_pref_action.go", "set_nexthop_action.go", diff --git a/routingtable/filter/actions/accept_action.go b/routingtable/filter/actions/accept_action.go index 6c0cc2acbfa3d75603ff33cc10025bdad09b3a23..6e340d5394a178066b0b7dfa45c60e46590de3ff 100644 --- a/routingtable/filter/actions/accept_action.go +++ b/routingtable/filter/actions/accept_action.go @@ -8,6 +8,9 @@ import ( type AcceptAction struct { } -func (*AcceptAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { - return pa, false +func (*AcceptAction) Do(p net.Prefix, pa *route.Path) Result { + return Result{ + Path: pa, + Terminate: true, + } } diff --git a/routingtable/filter/actions/action.go b/routingtable/filter/actions/action.go new file mode 100644 index 0000000000000000000000000000000000000000..3cd6f0ac746ae168eb5c6fa8c6eb7f7d2fea9a75 --- /dev/null +++ b/routingtable/filter/actions/action.go @@ -0,0 +1,11 @@ +package actions + +import ( + "github.com/bio-routing/bio-rd/route" +) + +type Result struct { + Path *route.Path + Reject bool + Terminate bool +} diff --git a/routingtable/filter/actions/add_community_action.go b/routingtable/filter/actions/add_community_action.go index c24107e8b94be6657174fbd3dffb06ae978ff767..4931056afc9bc901bef92b502e67775ee4e61d5c 100644 --- a/routingtable/filter/actions/add_community_action.go +++ b/routingtable/filter/actions/add_community_action.go @@ -15,9 +15,9 @@ func NewAddCommunityAction(coms []uint32) *AddCommunityAction { } } -func (a *AddCommunityAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { +func (a *AddCommunityAction) Do(p net.Prefix, pa *route.Path) Result { if pa.BGPPath == nil || len(a.communities) == 0 { - return pa, false + return Result{Path: pa} } modified := pa.Copy() @@ -26,5 +26,5 @@ func (a *AddCommunityAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Pa modified.BGPPath.Communities = append(modified.BGPPath.Communities, com) } - return modified, false + return Result{Path: modified} } diff --git a/routingtable/filter/actions/add_community_action_test.go b/routingtable/filter/actions/add_community_action_test.go index 9ec3d1401b87da808c324a984e1d5ef7620658cd..3527437b9efab61df4bd5203848318bbbf87849d 100644 --- a/routingtable/filter/actions/add_community_action_test.go +++ b/routingtable/filter/actions/add_community_action_test.go @@ -53,9 +53,9 @@ func TestAddingCommunities(t *testing.T) { } a := NewAddCommunityAction(test.communities) - modPath, _ := a.Do(net.Prefix{}, p) + res := a.Do(net.Prefix{}, p) - assert.Equal(t, test.expected, modPath.BGPPath.CommunitiesString()) + assert.Equal(t, test.expected, res.Path.BGPPath.CommunitiesString()) }) } } diff --git a/routingtable/filter/actions/add_large_community_action.go b/routingtable/filter/actions/add_large_community_action.go index cb5f1a020ea6bfdde33948cc8535077df0fec26d..9e0a9da44955a1779ce8655551d09a3a31f077d4 100644 --- a/routingtable/filter/actions/add_large_community_action.go +++ b/routingtable/filter/actions/add_large_community_action.go @@ -16,13 +16,13 @@ func NewAddLargeCommunityAction(coms []types.LargeCommunity) *AddLargeCommunityA } } -func (a *AddLargeCommunityAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { +func (a *AddLargeCommunityAction) Do(p net.Prefix, pa *route.Path) Result { if pa.BGPPath == nil || len(a.communities) == 0 { - return pa, false + return Result{Path: pa} } modified := pa.Copy() modified.BGPPath.LargeCommunities = append(modified.BGPPath.LargeCommunities, a.communities...) - return modified, false + return Result{Path: modified} } diff --git a/routingtable/filter/actions/add_large_community_action_test.go b/routingtable/filter/actions/add_large_community_action_test.go index 6b569d2ebd79e7225791b0172c2ad32fab764d88..fe077817e5098a9966efc11a7d7d03e905212460 100644 --- a/routingtable/filter/actions/add_large_community_action_test.go +++ b/routingtable/filter/actions/add_large_community_action_test.go @@ -71,7 +71,7 @@ func TestAddingLargeCommunities(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(te *testing.T) { + t.Run(test.name, func(t *testing.T) { p := &route.Path{ BGPPath: &route.BGPPath{ LargeCommunities: test.current, @@ -79,9 +79,9 @@ func TestAddingLargeCommunities(t *testing.T) { } a := NewAddLargeCommunityAction(test.communities) - modPath, _ := a.Do(net.Prefix{}, p) + res := a.Do(net.Prefix{}, p) - assert.Equal(te, test.expected, modPath.BGPPath.LargeCommunitiesString()) + assert.Equal(t, test.expected, res.Path.BGPPath.LargeCommunitiesString()) }) } } diff --git a/routingtable/filter/actions/as_path_prepend_action.go b/routingtable/filter/actions/as_path_prepend_action.go index 30d63ca783fd91a9530f336f3311106c57ac5968..2e53b1e84526aec2e092b3fea3bb1056dc360f2a 100644 --- a/routingtable/filter/actions/as_path_prepend_action.go +++ b/routingtable/filter/actions/as_path_prepend_action.go @@ -17,13 +17,13 @@ func NewASPathPrependAction(asn uint32, times uint16) *ASPathPrependAction { } } -func (a *ASPathPrependAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { +func (a *ASPathPrependAction) Do(p net.Prefix, pa *route.Path) Result { if pa.BGPPath == nil { - return pa, false + return Result{Path: pa} } modified := pa.Copy() modified.BGPPath.Prepend(a.asn, a.times) - return modified, false + return Result{Path: modified} } diff --git a/routingtable/filter/actions/as_path_prepend_action_test.go b/routingtable/filter/actions/as_path_prepend_action_test.go index f7c7af59394670a51c6062d43df19ae45ec69eb2..12cc0267f22b9a2bbe32f334c0aeb4f3f48bcf30 100644 --- a/routingtable/filter/actions/as_path_prepend_action_test.go +++ b/routingtable/filter/actions/as_path_prepend_action_test.go @@ -54,9 +54,9 @@ func TestAppendPath(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(te *testing.T) { + t.Run(test.name, func(t *testing.T) { a := NewASPathPrependAction(12345, test.times) - p, _ := a.Do(bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ + res := a.Do(bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ BGPPath: test.bgpPath, }) @@ -64,8 +64,8 @@ func TestAppendPath(t *testing.T) { return } - assert.Equal(te, test.expectedPath, p.BGPPath.ASPath.String(), "ASPath") - assert.Equal(te, test.expectedLength, p.BGPPath.ASPathLen, "ASPathLen") + assert.Equal(t, test.expectedPath, res.Path.BGPPath.ASPath.String(), "ASPath") + assert.Equal(t, test.expectedLength, res.Path.BGPPath.ASPathLen, "ASPathLen") }) } } diff --git a/routingtable/filter/actions/filter_action.go b/routingtable/filter/actions/filter_action.go deleted file mode 100644 index 7a2665146922719766b880f9093eb1049c6ae018..0000000000000000000000000000000000000000 --- a/routingtable/filter/actions/filter_action.go +++ /dev/null @@ -1,10 +0,0 @@ -package actions - -import ( - "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/route" -) - -type FilterAction interface { - Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) -} diff --git a/routingtable/filter/actions/reject_action.go b/routingtable/filter/actions/reject_action.go index d740139626b99395db71a3b2e7c2cea1d04ebacf..4693bbfaad45aa8f0b83e914733834a6a52a99f8 100644 --- a/routingtable/filter/actions/reject_action.go +++ b/routingtable/filter/actions/reject_action.go @@ -8,6 +8,10 @@ import ( type RejectAction struct { } -func (*RejectAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { - return pa, true +func (*RejectAction) Do(p net.Prefix, pa *route.Path) Result { + return Result{ + Path: pa, + Reject: true, + Terminate: true, + } } diff --git a/routingtable/filter/actions/set_local_pref_action.go b/routingtable/filter/actions/set_local_pref_action.go index e60b6faa0ab5e4e986f785d7b8322db2c6492e34..26d038ec0ad0f0f4d110bb1fdb9bfc3e08c67458 100644 --- a/routingtable/filter/actions/set_local_pref_action.go +++ b/routingtable/filter/actions/set_local_pref_action.go @@ -15,13 +15,13 @@ func NewSetLocalPrefAction(pref uint32) *SetLocalPrefAction { } } -func (a *SetLocalPrefAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { +func (a *SetLocalPrefAction) Do(p net.Prefix, pa *route.Path) Result { if pa.BGPPath == nil { - return pa, false + return Result{Path: pa} } modified := *pa modified.BGPPath.LocalPref = a.pref - return &modified, false + return Result{Path: &modified} } diff --git a/routingtable/filter/actions/set_local_pref_action_test.go b/routingtable/filter/actions/set_local_pref_action_test.go index 7b104d3949d127e794dcd34a2a05a7b7aa3f2b02..40ef0f6b3e649c6dc2cf45d3ba6b31fd6b8862b0 100644 --- a/routingtable/filter/actions/set_local_pref_action_test.go +++ b/routingtable/filter/actions/set_local_pref_action_test.go @@ -27,14 +27,14 @@ func TestSetLocalPref(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(te *testing.T) { + t.Run(test.name, func(t *testing.T) { a := NewSetLocalPrefAction(150) - p, _ := a.Do(bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ + res := a.Do(bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ BGPPath: test.bgpPath, }) if test.expectedLocalPref > 0 { - assert.Equal(te, test.expectedLocalPref, p.BGPPath.LocalPref) + assert.Equal(t, test.expectedLocalPref, res.Path.BGPPath.LocalPref) } }) } diff --git a/routingtable/filter/actions/set_nexthop_action.go b/routingtable/filter/actions/set_nexthop_action.go index de1e9bc959b8f9d827c48c844699aa2aed92fda9..8b00a8717744611d2bd17661b201973b727026bb 100644 --- a/routingtable/filter/actions/set_nexthop_action.go +++ b/routingtable/filter/actions/set_nexthop_action.go @@ -16,13 +16,13 @@ func NewSetNextHopAction(ip bnet.IP) *SetNextHopAction { } } -func (a *SetNextHopAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { +func (a *SetNextHopAction) Do(p net.Prefix, pa *route.Path) Result { if pa.BGPPath == nil { - return pa, false + return Result{Path: pa} } modified := pa.Copy() modified.BGPPath.NextHop = a.ip - return modified, false + return Result{Path: modified} } diff --git a/routingtable/filter/actions/set_nexthop_action_test.go b/routingtable/filter/actions/set_nexthop_action_test.go index 7f691d235f288e1155980ea997b4e6fddaa6a4de..bebbafebbd6fec029e7a74dad4b4fda9e2a50f29 100644 --- a/routingtable/filter/actions/set_nexthop_action_test.go +++ b/routingtable/filter/actions/set_nexthop_action_test.go @@ -31,12 +31,12 @@ func TestSetNextHopTest(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { a := NewSetNextHopAction(bnet.IPv4FromOctets(100, 64, 2, 1)) - p, _ := a.Do(net.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ + res := a.Do(net.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{ BGPPath: test.bgpPath, }) if test.bgpPath != nil { - assert.Equal(t, test.expected, p.BGPPath.NextHop) + assert.Equal(t, test.expected, res.Path.BGPPath.NextHop) } }) } diff --git a/routingtable/filter/filter.go b/routingtable/filter/filter.go index cb88087983c31ebb2a5b58bf7a002117c829efb7..27f3b1f4fc69b4c879a8268408f4539add3183cd 100644 --- a/routingtable/filter/filter.go +++ b/routingtable/filter/filter.go @@ -21,10 +21,11 @@ func (f *Filter) ProcessTerms(p net.Prefix, pa *route.Path) (modPath *route.Path modPath = pa for _, t := range f.terms { - modPath, reject = t.Process(p, modPath) - if reject { - return modPath, true + res := t.Process(p, modPath) + if res.Terminate { + return res.Path, res.Reject } + modPath = res.Path } return modPath, false diff --git a/routingtable/filter/filter_test.go b/routingtable/filter/filter_test.go index 52ebc8b9180aab9429b22489d75db95e210d2f65..0eeb4942df0938d3445a4df6598ac523fa2d577f 100644 --- a/routingtable/filter/filter_test.go +++ b/routingtable/filter/filter_test.go @@ -23,7 +23,7 @@ func TestProcessTerms(t *testing.T) { prefix: net.NewPfx(net.IPv4(0), 0), path: &route.Path{}, term: &Term{ - then: []FilterAction{ + then: []Action{ &actions.AcceptAction{}, }, }, @@ -35,19 +35,32 @@ func TestProcessTerms(t *testing.T) { prefix: net.NewPfx(net.IPv4(0), 0), path: &route.Path{}, term: &Term{ - then: []FilterAction{ + then: []Action{ &actions.RejectAction{}, }, }, exptectAccept: false, expectModified: false, }, + { + name: "accept before reject", + prefix: net.NewPfx(net.IPv4(0), 0), + path: &route.Path{}, + term: &Term{ + then: []Action{ + &actions.AcceptAction{}, + &actions.RejectAction{}, + }, + }, + exptectAccept: true, + expectModified: false, + }, { name: "modified", prefix: net.NewPfx(net.IPv4(0), 0), path: &route.Path{}, term: &Term{ - then: []FilterAction{ + then: []Action{ &mockAction{}, &actions.AcceptAction{}, }, @@ -58,7 +71,7 @@ func TestProcessTerms(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(te *testing.T) { + t.Run(test.name, func(t *testing.T) { f := NewFilter([]*Term{test.term}) p, reject := f.ProcessTerms(test.prefix, test.path) diff --git a/routingtable/filter/helper.go b/routingtable/filter/helper.go index 17a7d73789d5be569bec1725592a35f1b3841386..1cfb6e5c8be7ea13e3e76a8609b8307b48e665e9 100644 --- a/routingtable/filter/helper.go +++ b/routingtable/filter/helper.go @@ -10,7 +10,7 @@ func NewAcceptAllFilter() *Filter { []*Term{ NewTerm( []*TermCondition{}, - []FilterAction{ + []Action{ &actions.AcceptAction{}, }), }) @@ -22,7 +22,7 @@ func NewDrainFilter() *Filter { []*Term{ NewTerm( []*TermCondition{}, - []FilterAction{ + []Action{ &actions.RejectAction{}, }), }) diff --git a/routingtable/filter/term.go b/routingtable/filter/term.go index d644acba4a977e67e757fc5c7f71863531427e12..cdf56c7fa90eff0a0f844377a27985900235231d 100644 --- a/routingtable/filter/term.go +++ b/routingtable/filter/term.go @@ -5,18 +5,20 @@ import ( "github.com/bio-routing/bio-rd/route" ) -type FilterAction interface { - Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) -} - // Term matches a path against a list of conditions and performs actions if it matches type Term struct { from []*TermCondition - then []FilterAction + then []Action +} + +type TermResult struct { + Path *route.Path + Terminate bool + Reject bool } // NewTerm creates a new term -func NewTerm(from []*TermCondition, then []FilterAction) *Term { +func NewTerm(from []*TermCondition, then []Action) *Term { t := &Term{ from: from, then: then, @@ -26,7 +28,7 @@ func NewTerm(from []*TermCondition, then []FilterAction) *Term { } // 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) { +func (t *Term) Process(p net.Prefix, pa *route.Path) TermResult { orig := pa if len(t.from) == 0 { @@ -39,18 +41,23 @@ func (t *Term) Process(p net.Prefix, pa *route.Path) (modPath *route.Path, rejec } } - return orig, false + return TermResult{Path: orig} } -func (t *Term) processActions(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) { - modPath = pa +func (t *Term) processActions(p net.Prefix, pa *route.Path) TermResult { + modPath := pa for _, action := range t.then { - modPath, reject = action.Do(p, modPath) - if reject { - continue + res := action.Do(p, modPath) + if res.Terminate { + return TermResult{ + Path: modPath, + Terminate: true, + Reject: res.Reject, + } } + modPath = res.Path } - return modPath, reject + return TermResult{Path: modPath} } diff --git a/routingtable/filter/term_test.go b/routingtable/filter/term_test.go index 876eb6691ec33a0a95697267f171ace3307d8a83..591fd234befde8d15538dd7cf293a9922479560d 100644 --- a/routingtable/filter/term_test.go +++ b/routingtable/filter/term_test.go @@ -12,11 +12,11 @@ import ( type mockAction struct { } -func (*mockAction) Do(p net.Prefix, pa *route.Path) (*route.Path, bool) { +func (*mockAction) Do(p net.Prefix, pa *route.Path) actions.Result { cp := *pa cp.Type = route.OSPFPathType - return &cp, false + return actions.Result{Path: &cp} } func TestProcess(t *testing.T) { @@ -25,7 +25,7 @@ func TestProcess(t *testing.T) { prefix net.Prefix path *route.Path from []*TermCondition - then []FilterAction + then []Action expectReject bool expectModified bool }{ @@ -34,7 +34,7 @@ func TestProcess(t *testing.T) { prefix: net.NewPfx(net.IPv4FromOctets(100, 64, 0, 1), 8), path: &route.Path{}, from: []*TermCondition{}, - then: []FilterAction{ + then: []Action{ &actions.AcceptAction{}, }, expectReject: false, @@ -48,7 +48,7 @@ func TestProcess(t *testing.T) { NewTermConditionWithPrefixLists( NewPrefixList(net.NewPfx(net.IPv4FromOctets(100, 64, 0, 1), 8))), }, - then: []FilterAction{ + then: []Action{ &actions.AcceptAction{}, }, expectReject: false, @@ -62,7 +62,7 @@ func TestProcess(t *testing.T) { NewTermConditionWithPrefixLists( NewPrefixList(net.NewPfx(net.IPv4(0), 32))), }, - then: []FilterAction{ + then: []Action{ &actions.AcceptAction{}, }, expectReject: false, @@ -76,7 +76,7 @@ func TestProcess(t *testing.T) { NewTermConditionWithPrefixLists( NewPrefixList(net.NewPfx(net.IPv4FromOctets(100, 64, 0, 1), 8))), }, - then: []FilterAction{ + then: []Action{ &mockAction{}, }, expectReject: false, @@ -90,7 +90,7 @@ func TestProcess(t *testing.T) { NewTermConditionWithRouteFilters( NewRouteFilter(net.NewPfx(net.IPv4FromOctets(100, 64, 0, 1), 8), Exact())), }, - then: []FilterAction{ + then: []Action{ &mockAction{}, &actions.AcceptAction{}, }, @@ -109,7 +109,7 @@ func TestProcess(t *testing.T) { }, }, }, - then: []FilterAction{ + then: []Action{ &actions.AcceptAction{}, }, expectReject: false, @@ -118,18 +118,18 @@ func TestProcess(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(te *testing.T) { + t.Run(test.name, func(t *testing.T) { term := NewTerm(test.from, test.then) - pa, reject := term.Process(test.prefix, test.path) - assert.Equal(te, test.expectReject, reject, "reject") + res := term.Process(test.prefix, test.path) + assert.Equal(t, test.expectReject, res.Reject, "reject") - if pa != test.path && !test.expectModified { - te.Fatal("expected path to be not modified but was") + if res.Path != test.path && !test.expectModified { + t.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") + if res.Path == test.path && test.expectModified { + t.Fatal("expected path to be modified but was same reference") } }) }