From ec36861743e6788910c1bc3be0f32eb7627ec715 Mon Sep 17 00:00:00 2001
From: Daniel Czerwonk <daniel@dan-nrw.de>
Date: Fri, 1 Jun 2018 20:34:10 +0200
Subject: [PATCH] added community filter

---
 routingtable/filter/community_filter.go    | 15 +++++++++++++++
 routingtable/filter/term_condition.go      | 20 +++++++++++++++++++-
 routingtable/filter/term_condition_test.go | 21 +++++++++++++++++++++
 3 files changed, 55 insertions(+), 1 deletion(-)
 create mode 100644 routingtable/filter/community_filter.go

diff --git a/routingtable/filter/community_filter.go b/routingtable/filter/community_filter.go
new file mode 100644
index 00000000..9d384e54
--- /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 003b9dcb..a7e0a433 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 6e9b89f2..3d8558ab 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{
-- 
GitLab