diff --git a/routingtable/filter/community_filter.go b/routingtable/filter/community_filter.go new file mode 100644 index 0000000000000000000000000000000000000000..9d384e54ad0a58ee622e3d2b0bb1b857c867b0c3 --- /dev/null +++ b/routingtable/filter/community_filter.go @@ -0,0 +1,15 @@ +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)) +} diff --git a/routingtable/filter/term_condition.go b/routingtable/filter/term_condition.go index 003b9dcbc021e75cd28d3039efbad2d00bf1d109..a7e0a4330d21e1678d8aacc03e429632506cf61b 100644 --- a/routingtable/filter/term_condition.go +++ b/routingtable/filter/term_condition.go @@ -8,6 +8,7 @@ import ( type TermCondition struct { prefixLists []*PrefixList routeFilters []*RouteFilter + communityFilters []*CommunityFilter largeCommunityFilters []*LargeCommunityFilter } @@ -19,7 +20,10 @@ func NewTermCondition(prefixLists []*PrefixList, routeFilters []*RouteFilter) *T } func (f *TermCondition) Matches(p net.Prefix, pa *route.Path) bool { - return f.matchesAnyPrefixList(p) || f.machtchesAnyRouteFilter(p) || f.machtchesAnyLageCommunityFilter(pa) + return f.matchesAnyPrefixList(p) || + f.machtchesAnyRouteFilter(p) || + f.machtchesAnyLageCommunityFilter(pa) || + f.machtchesAnyCommunityFilter(pa) } func (t *TermCondition) matchesAnyPrefixList(p net.Prefix) bool { @@ -42,6 +46,20 @@ func (t *TermCondition) machtchesAnyRouteFilter(p net.Prefix) bool { return false } +func (t *TermCondition) machtchesAnyCommunityFilter(pa *route.Path) bool { + if pa.BGPPath == nil { + return false + } + + for _, l := range t.communityFilters { + if l.Matches(pa.BGPPath.Communities) { + return true + } + } + + return false +} + func (t *TermCondition) machtchesAnyLageCommunityFilter(pa *route.Path) bool { if pa.BGPPath == nil { return false diff --git a/routingtable/filter/term_condition_test.go b/routingtable/filter/term_condition_test.go index 6e9b89f20eb226faebdd3856fa4bc61a97388a4e..3d8558ab2d47abf957c5f8e294edccf06ab6fbb4 100644 --- a/routingtable/filter/term_condition_test.go +++ b/routingtable/filter/term_condition_test.go @@ -16,6 +16,7 @@ func TestMatches(t *testing.T) { bgpPath *route.BGPPath prefixLists []*PrefixList routeFilters []*RouteFilter + communityFilters []*CommunityFilter largeCommunityFilters []*LargeCommunityFilter expected bool }{ @@ -108,6 +109,25 @@ func TestMatches(t *testing.T) { }, expected: true, }, + { + 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, + }, + { + name: "community does not match", + prefix: net.NewPfx(strAddr("10.0.0.0"), 24), + communityFilters: []*CommunityFilter{ + &CommunityFilter{196608}, // (3,0) + }, + expected: false, + }, { name: "large community matches", prefix: net.NewPfx(strAddr("10.0.0.0"), 24), @@ -145,6 +165,7 @@ func TestMatches(t *testing.T) { for _, test := range tests { t.Run(test.name, func(te *testing.T) { f := NewTermCondition(test.prefixLists, test.routeFilters) + f.communityFilters = test.communityFilters f.largeCommunityFilters = test.largeCommunityFilters pa := &route.Path{