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

Merge pull request #39 from bio-routing/feature/community_filters

Feature/community filters
parents 7fd338f8 c8a05e1d
No related branches found
No related tags found
No related merge requests found
...@@ -13,7 +13,7 @@ const ( ...@@ -13,7 +13,7 @@ const (
func CommunityStringForUint32(v uint32) string { func CommunityStringForUint32(v uint32) string {
e1 := v >> 16 e1 := v >> 16
e2 := v - e1<<16 e2 := v & 0x0000FFFF
return fmt.Sprintf("(%d,%d)", e1, e2) return fmt.Sprintf("(%d,%d)", e1, e2)
} }
......
package actions
import (
"strings"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/protocols/bgp/packet"
"github.com/bio-routing/bio-rd/route"
)
type AddCommunityAction struct {
communities []uint32
}
func NewAddCommunityAction(coms []uint32) *AddCommunityAction {
return &AddCommunityAction{
communities: coms,
}
}
func (a *AddCommunityAction) Do(p net.Prefix, pa *route.Path) (modPath *route.Path, reject bool) {
if pa.BGPPath == nil || len(a.communities) == 0 {
return pa, false
}
modified := pa.Copy()
for _, com := range a.communities {
modified.BGPPath.Communities = modified.BGPPath.Communities + " " + packet.CommunityStringForUint32(com)
}
modified.BGPPath.Communities = strings.TrimLeft(modified.BGPPath.Communities, " ")
return modified, false
}
package actions
import (
"testing"
"github.com/bio-routing/bio-rd/net"
"github.com/bio-routing/bio-rd/route"
"github.com/stretchr/testify/assert"
)
func TestAddingCommunities(t *testing.T) {
tests := []struct {
name string
current string
communities []uint32
expected string
}{
{
name: "add one to empty",
communities: []uint32{
65538,
},
expected: "(1,2)",
},
{
name: "add one to existing",
current: "(1,2)",
communities: []uint32{
196612,
},
expected: "(1,2) (3,4)",
},
{
name: "add two to existing",
current: "(1,2)",
communities: []uint32{
196612, 327686,
},
expected: "(1,2) (3,4) (5,6)",
},
}
for _, test := range tests {
t.Run(test.name, func(te *testing.T) {
p := &route.Path{
BGPPath: &route.BGPPath{
Communities: test.current,
},
}
a := NewAddCommunityAction(test.communities)
modPath, _ := a.Do(net.Prefix{}, p)
assert.Equal(te, test.expected, modPath.BGPPath.Communities)
})
}
}
package filter
import (
"strings"
"github.com/bio-routing/bio-rd/protocols/bgp/packet"
)
type CommunityFilter struct {
community uint32
}
func (f *CommunityFilter) Matches(communityString string) bool {
return strings.Contains(communityString, packet.CommunityStringForUint32(f.community))
}
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
type TermCondition struct { type TermCondition struct {
prefixLists []*PrefixList prefixLists []*PrefixList
routeFilters []*RouteFilter routeFilters []*RouteFilter
communityFilters []*CommunityFilter
largeCommunityFilters []*LargeCommunityFilter largeCommunityFilters []*LargeCommunityFilter
} }
...@@ -19,10 +20,17 @@ func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *T ...@@ -19,10 +20,17 @@ func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *T
} }
func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool { func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool {
return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) || f.machtchesAnyLageCommunityFilter(pa) return f.matchesPrefixListFilters(p) &&
f.machtchesRouteFilters(p) &&
f.machtchesCommunityFilters(pa) &&
f.machtchesLargeCommunityFilters(pa)
} }
func (t *TermCondition) matchesAnyPrefixList(p net.Prefix) bool { func (t *TermCondition) matchesPrefixListFilters(p net.Prefix) bool {
if len(t.prefixLists) == 0 {
return true
}
for _, l := range t.prefixLists { for _, l := range t.prefixLists {
if l.Matches(p) { if l.Matches(p) {
return true return true
...@@ -32,7 +40,11 @@ func (t *TermCondition) matchesAnyPrefixList(p net.Prefix) bool { ...@@ -32,7 +40,11 @@ func (t *TermCondition) matchesAnyPrefixList(p net.Prefix) bool {
return false return false
} }
func (t *TermCondition) machtchesAnyRouteFilter(p net.Prefix) bool { func (t *TermCondition) machtchesRouteFilters(p net.Prefix) bool {
if len(t.routeFilters) == 0 {
return true
}
for _, l := range t.routeFilters { for _, l := range t.routeFilters {
if l.Matches(p) { if l.Matches(p) {
return true return true
...@@ -42,7 +54,29 @@ func (t *TermCondition) machtchesAnyRouteFilter(p net.Prefix) bool { ...@@ -42,7 +54,29 @@ func (t *TermCondition) machtchesAnyRouteFilter(p net.Prefix) bool {
return false return false
} }
func (t *TermCondition) machtchesAnyLageCommunityFilter(pa *route.Path) bool { func (t *TermCondition) machtchesCommunityFilters(pa *route.Path) bool {
if len(t.communityFilters) == 0 {
return true
}
if pa.BGPPath == nil {
return false
}
for _, l := range t.communityFilters {
if l.Matches(pa.BGPPath.Communities) {
return true
}
}
return false
}
func (t *TermCondition) machtchesLargeCommunityFilters(pa *route.Path) bool {
if len(t.largeCommunityFilters) == 0 {
return true
}
if pa.BGPPath == nil { if pa.BGPPath == nil {
return false return false
} }
......
...@@ -16,6 +16,7 @@ func TestMatches(t *testing.T) { ...@@ -16,6 +16,7 @@ func TestMatches(t *testing.T) {
bgpPath *route.BGPPath bgpPath *route.BGPPath
prefixLists []*PrefixList prefixLists []*PrefixList
routeFilters []*RouteFilter routeFilters []*RouteFilter
communityFilters []*CommunityFilter
largeCommunityFilters []*LargeCommunityFilter largeCommunityFilters []*LargeCommunityFilter
expected bool expected bool
}{ }{
...@@ -25,8 +26,7 @@ func TestMatches(t *testing.T) { ...@@ -25,8 +26,7 @@ func TestMatches(t *testing.T) {
prefixLists: []*PrefixList{ prefixLists: []*PrefixList{
NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)), NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)),
}, },
routeFilters: []*RouteFilter{}, expected: true,
expected: true,
}, },
{ {
name: "one prefix in prefix list and no match, no route filters set", name: "one prefix in prefix list and no match, no route filters set",
...@@ -34,8 +34,7 @@ func TestMatches(t *testing.T) { ...@@ -34,8 +34,7 @@ func TestMatches(t *testing.T) {
prefixLists: []*PrefixList{ prefixLists: []*PrefixList{
NewPrefixList(net.NewPfx(0, 32)), NewPrefixList(net.NewPfx(0, 32)),
}, },
routeFilters: []*RouteFilter{}, expected: false,
expected: false,
}, },
{ {
name: "one prefix of 2 matches in prefix list, no route filters set", name: "one prefix of 2 matches in prefix list, no route filters set",
...@@ -44,22 +43,19 @@ func TestMatches(t *testing.T) { ...@@ -44,22 +43,19 @@ func TestMatches(t *testing.T) {
NewPrefixList(net.NewPfx(strAddr("10.0.0.0"), 8)), NewPrefixList(net.NewPfx(strAddr("10.0.0.0"), 8)),
NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)), NewPrefixList(net.NewPfx(strAddr("127.0.0.1"), 8)),
}, },
routeFilters: []*RouteFilter{}, expected: true,
expected: true,
}, },
{ {
name: "no prefixes in prefix list, only route filter matches", name: "no prefixes in prefix list, only route filter matches",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24), prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
prefixLists: []*PrefixList{},
routeFilters: []*RouteFilter{ routeFilters: []*RouteFilter{
NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
}, },
expected: true, expected: true,
}, },
{ {
name: "no prefixes in prefix list, one route filter matches", name: "no prefixes in prefix list, one route filter matches",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24), prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
prefixLists: []*PrefixList{},
routeFilters: []*RouteFilter{ routeFilters: []*RouteFilter{
NewRouteFilter(net.NewPfx(strAddr("8.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("8.0.0.0"), 8), Longer()),
NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
...@@ -67,9 +63,8 @@ func TestMatches(t *testing.T) { ...@@ -67,9 +63,8 @@ func TestMatches(t *testing.T) {
expected: true, expected: true,
}, },
{ {
name: "no prefixes in prefix list, one of many route filters matches", name: "no prefixes in prefix list, one of many route filters matches",
prefix: net.NewPfx(strAddr("127.0.0.1"), 8), prefix: net.NewPfx(strAddr("127.0.0.1"), 8),
prefixLists: []*PrefixList{},
routeFilters: []*RouteFilter{ routeFilters: []*RouteFilter{
NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
}, },
...@@ -87,7 +82,7 @@ func TestMatches(t *testing.T) { ...@@ -87,7 +82,7 @@ func TestMatches(t *testing.T) {
expected: false, expected: false,
}, },
{ {
name: "one prefix in prefixlist, one route fitler, only prefix list matches", name: "one prefix in prefixlist, one route filter, only prefix list matches",
prefix: net.NewPfx(strAddr("8.8.8.0"), 24), prefix: net.NewPfx(strAddr("8.8.8.0"), 24),
prefixLists: []*PrefixList{ prefixLists: []*PrefixList{
NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)), NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)),
...@@ -95,10 +90,10 @@ func TestMatches(t *testing.T) { ...@@ -95,10 +90,10 @@ func TestMatches(t *testing.T) {
routeFilters: []*RouteFilter{ routeFilters: []*RouteFilter{
NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
}, },
expected: true, expected: false,
}, },
{ {
name: "one prefix in prefixlist, one route fitler, only route filter matches", name: "one prefix in prefixlist, one route filter, only route filter matches",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24), prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
prefixLists: []*PrefixList{ prefixLists: []*PrefixList{
NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)), NewPrefixList(net.NewPfx(strAddr("8.0.0.0"), 8)),
...@@ -106,8 +101,38 @@ func TestMatches(t *testing.T) { ...@@ -106,8 +101,38 @@ func TestMatches(t *testing.T) {
routeFilters: []*RouteFilter{ routeFilters: []*RouteFilter{
NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()), NewRouteFilter(net.NewPfx(strAddr("10.0.0.0"), 8), Longer()),
}, },
expected: false,
},
{
name: "community matches",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
bgpPath: &route.BGPPath{
Communities: "(1,2) (3,4) (5,6)",
},
communityFilters: []*CommunityFilter{
&CommunityFilter{196612}, // (3,4)
},
expected: true, expected: true,
}, },
{
name: "community does not match",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
bgpPath: &route.BGPPath{
Communities: "(1,2) (3,4) (5,6)",
},
communityFilters: []*CommunityFilter{
&CommunityFilter{196608}, // (3,0)
},
expected: false,
},
{
name: "community filter, bgp path is nil",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
communityFilters: []*CommunityFilter{
&CommunityFilter{196608}, // (3,0)
},
expected: false,
},
{ {
name: "large community matches", name: "large community matches",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24), prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
...@@ -140,11 +165,26 @@ func TestMatches(t *testing.T) { ...@@ -140,11 +165,26 @@ func TestMatches(t *testing.T) {
}, },
expected: false, expected: false,
}, },
{
name: "large community filter, bgp path is nil",
prefix: net.NewPfx(strAddr("10.0.0.0"), 24),
largeCommunityFilters: []*LargeCommunityFilter{
{
&packet.LargeCommunity{
GlobalAdministrator: 1,
DataPart1: 2,
DataPart2: 3,
},
},
},
expected: false,
},
} }
for _, test := range tests { for _, test := range tests {
t.Run(test.name, func(te *testing.T) { t.Run(test.name, func(te *testing.T) {
f := NewTermCondition(test.prefixLists, test.routeFilters) f := NewTermCondition(test.prefixLists, test.routeFilters)
f.communityFilters = test.communityFilters
f.largeCommunityFilters = test.largeCommunityFilters f.largeCommunityFilters = test.largeCommunityFilters
pa := &route.Path{ pa := &route.Path{
......
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