diff --git a/routingtable/filter/large_community_filter.go b/routingtable/filter/large_community_filter.go new file mode 100644 index 0000000000000000000000000000000000000000..0f9d474e69728ba682cde441e819a0d08bd7cc77 --- /dev/null +++ b/routingtable/filter/large_community_filter.go @@ -0,0 +1,15 @@ +package filter + +import ( + "strings" + + "github.com/bio-routing/bio-rd/protocols/bgp/packet" +) + +type LargeCommunityFilter struct { + community *packet.LargeCommunity +} + +func (f *LargeCommunityFilter) Matches(communityString string) bool { + return strings.Contains(communityString, f.community.String()) +} diff --git a/routingtable/filter/term_condition.go b/routingtable/filter/term_condition.go index 92c3616a8cc55f21c73696b2f87a1b2a9cfbcbd4..946a04e85781d160dd893dab84588a965ff9190e 100644 --- a/routingtable/filter/term_condition.go +++ b/routingtable/filter/term_condition.go @@ -6,12 +6,13 @@ import ( ) type TermCondition struct { - prefixLists []*PrefixList - routeFilters []*RouteFilter + prefixLists []*PrefixList + routeFilters []*RouteFilter + largeCommunityFilters []*LargeCommunityFilter } func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool { - return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) + return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) || f.machtchesAnyLageCommunityFilter(pa) } func (t *TermCondition) matchesAnyPrefixList(p net.Prefix) bool { @@ -33,3 +34,17 @@ func (t *TermCondition) machtchesAnyRouteFilter(p net.Prefix) bool { return false } + +func (t *TermCondition) machtchesAnyLageCommunityFilter(pa *route.Path) bool { + if pa.BGPPath == nil { + return false + } + + for _, l := range t.largeCommunityFilters { + if l.Matches(pa.BGPPath.LargeCommunities) { + return true + } + } + + return false +} diff --git a/routingtable/filter/term_condition_test.go b/routingtable/filter/term_condition_test.go index 876746a240d195ee2a6612636a888a2cf41a9d25..307cd5e0485d6388661c61c4f67cf1c2a4bdb9bd 100644 --- a/routingtable/filter/term_condition_test.go +++ b/routingtable/filter/term_condition_test.go @@ -4,17 +4,20 @@ import ( "testing" "github.com/bio-routing/bio-rd/net" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" "github.com/bio-routing/bio-rd/route" "github.com/stretchr/testify/assert" ) func TestMatches(t *testing.T) { tests := []struct { - name string - prefix net.Prefix - prefixLists []*PrefixList - routeFilters []*RouteFilter - expected bool + name string + prefix net.Prefix + bgpPath *route.BGPPath + prefixLists []*PrefixList + routeFilters []*RouteFilter + largeCommunityFilters []*LargeCommunityFilter + expected bool }{ { name: "one prefix matches in prefix list, no route filters set", @@ -105,16 +108,53 @@ func TestMatches(t *testing.T) { }, expected: true, }, + { + name: "large community matches", + prefix: net.NewPfx(strAddr("10.0.0.0"), 24), + bgpPath: &route.BGPPath{ + LargeCommunities: "(1,2,0) (1,2,3)", + }, + largeCommunityFilters: []*LargeCommunityFilter{ + { + &packet.LargeCommunity{ + GlobalAdministrator: 1, + DataPart1: 2, + DataPart2: 3, + }, + }, + }, + expected: true, + }, + { + name: "large community does not match", + prefix: net.NewPfx(strAddr("10.0.0.0"), 24), + bgpPath: &route.BGPPath{}, + largeCommunityFilters: []*LargeCommunityFilter{ + { + &packet.LargeCommunity{ + GlobalAdministrator: 1, + DataPart1: 2, + DataPart2: 3, + }, + }, + }, + expected: false, + }, } for _, test := range tests { t.Run(test.name, func(te *testing.T) { f := &TermCondition{ - prefixLists: test.prefixLists, - routeFilters: test.routeFilters, + prefixLists: test.prefixLists, + routeFilters: test.routeFilters, + largeCommunityFilters: test.largeCommunityFilters, + } + + pa := &route.Path{ + BGPPath: test.bgpPath, } - assert.Equal(te, test.expected, f.Matches(test.prefix, &route.Path{})) + assert.Equal(te, test.expected, f.Matches(test.prefix, pa)) }) } }