diff --git a/routingtable/filter/route_filter.go b/routingtable/filter/route_filter.go
new file mode 100644
index 0000000000000000000000000000000000000000..78a922fef4792f321d1563689a2b38ac5391f859
--- /dev/null
+++ b/routingtable/filter/route_filter.go
@@ -0,0 +1,48 @@
+package filter
+
+import (
+	"github.com/bio-routing/bio-rd/net"
+)
+
+type RouteFilter struct {
+	pattern net.Prefix
+	matcher PrefixMatcher
+}
+
+type PrefixMatcher func(pattern, prefix net.Prefix) bool
+
+func InRange(min, max uint8) PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		contains := pattern.Equal(prefix) || pattern.Contains(prefix)
+		return contains && prefix.Pfxlen() >= min && prefix.Pfxlen() <= max
+	}
+}
+
+func Exact() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Equal(prefix)
+	}
+}
+
+func OrLonger() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Equal(prefix) || pattern.Contains(prefix)
+	}
+}
+
+func Longer() PrefixMatcher {
+	return func(pattern, prefix net.Prefix) bool {
+		return pattern.Contains(prefix) && prefix.Pfxlen() > pattern.Pfxlen()
+	}
+}
+
+func NewRouteFilter(pattern net.Prefix, matcher PrefixMatcher) *RouteFilter {
+	return &RouteFilter{
+		pattern: pattern,
+		matcher: matcher,
+	}
+}
+
+func (f *RouteFilter) Matches(prefix net.Prefix) bool {
+	return f.matcher(f.pattern, prefix)
+}
diff --git a/routingtable/filter/route_filter_test.go b/routingtable/filter/route_filter_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7595df4dda19f8b4af5b668f972119878f5ab758
--- /dev/null
+++ b/routingtable/filter/route_filter_test.go
@@ -0,0 +1,198 @@
+package filter
+
+import (
+	"testing"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestInRange(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefix   net.Prefix
+		pattern  net.Prefix
+		begin    uint8
+		end      uint8
+		expected bool
+	}{
+		{
+			name:     "matches and in range (22-24)",
+			prefix:   net.NewPfx(strAddr("1.2.1.0"), 23),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 22),
+			begin:    22,
+			end:      24,
+			expected: true,
+		},
+		{
+			name:     "matches begin of range (22-24)",
+			prefix:   net.NewPfx(strAddr("1.2.0.0"), 22),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 22),
+			begin:    22,
+			end:      24,
+			expected: true,
+		},
+		{
+			name:     "matches end of range (22-24)",
+			prefix:   net.NewPfx(strAddr("1.2.128.0"), 24),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 22),
+			begin:    22,
+			end:      24,
+			expected: true,
+		},
+		{
+			name:     "matches begin and end of range (24-24)",
+			prefix:   net.NewPfx(strAddr("1.2.0.0"), 24),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 24),
+			begin:    24,
+			end:      24,
+			expected: true,
+		},
+		{
+			name:     "smaller (22-24)",
+			prefix:   net.NewPfx(strAddr("1.2.0.0"), 16),
+			pattern:  net.NewPfx(strAddr("1.2.4.0"), 22),
+			begin:    22,
+			end:      24,
+			expected: false,
+		},
+		{
+			name:     "longer (22-24)",
+			prefix:   net.NewPfx(strAddr("1.2.0.128"), 25),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 22),
+			begin:    22,
+			end:      24,
+			expected: false,
+		},
+		{
+			name:     "does not match",
+			prefix:   net.NewPfx(strAddr("2.0.0.0"), 23),
+			pattern:  net.NewPfx(strAddr("1.2.0.0"), 22),
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			f := NewRouteFilter(test.pattern, InRange(test.begin, test.end))
+			assert.Equal(te, test.expected, f.Matches(test.prefix))
+		})
+	}
+}
+
+func TestExact(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefix   net.Prefix
+		pattern  net.Prefix
+		expected bool
+	}{
+		{
+			name:     "matches (0.0.0.0/0)",
+			prefix:   net.NewPfx(strAddr("0.0.0.0"), 0),
+			pattern:  net.NewPfx(strAddr("0.0.0.0"), 0),
+			expected: true,
+		},
+		{
+			name:     "matches (192.168.0.0)",
+			prefix:   net.NewPfx(strAddr("192.168.1.1"), 24),
+			pattern:  net.NewPfx(strAddr("192.168.1.1"), 24),
+			expected: true,
+		},
+		{
+			name:     "does not match",
+			prefix:   net.NewPfx(strAddr("1.0.0.0"), 8),
+			pattern:  net.NewPfx(strAddr("0.0.0.0"), 0),
+			expected: false,
+		},
+		{
+			name:     "longer",
+			prefix:   net.NewPfx(strAddr("1.0.0.0"), 8),
+			pattern:  net.NewPfx(strAddr("1.0.0.0"), 7),
+			expected: false,
+		},
+		{
+			name:     "lesser",
+			prefix:   net.NewPfx(strAddr("1.0.0.0"), 7),
+			pattern:  net.NewPfx(strAddr("1.0.0.0"), 8),
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			f := NewRouteFilter(test.pattern, Exact())
+			assert.Equal(te, test.expected, f.Matches(test.prefix))
+		})
+	}
+}
+
+func TestOrLonger(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefix   net.Prefix
+		pattern  net.Prefix
+		expected bool
+	}{
+		{
+			name:     "longer",
+			prefix:   net.NewPfx(strAddr("1.2.3.128"), 25),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: true,
+		},
+		{
+			name:     "exact",
+			prefix:   net.NewPfx(strAddr("1.2.3.0"), 24),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: true,
+		},
+		{
+			name:     "lesser",
+			prefix:   net.NewPfx(strAddr("1.2.3.0"), 23),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			f := NewRouteFilter(test.pattern, OrLonger())
+			assert.Equal(te, test.expected, f.Matches(test.prefix))
+		})
+	}
+}
+
+func TestLonger(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefix   net.Prefix
+		pattern  net.Prefix
+		expected bool
+	}{
+		{
+			name:     "longer",
+			prefix:   net.NewPfx(strAddr("1.2.3.128"), 25),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: true,
+		},
+		{
+			name:     "exact",
+			prefix:   net.NewPfx(strAddr("1.2.3.0"), 24),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: false,
+		},
+		{
+			name:     "lesser",
+			prefix:   net.NewPfx(strAddr("1.2.3.0"), 23),
+			pattern:  net.NewPfx(strAddr("1.2.3.0"), 24),
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			f := NewRouteFilter(test.pattern, Longer())
+			assert.Equal(te, test.expected, f.Matches(test.prefix))
+		})
+	}
+}