diff --git a/rt/bgp.go b/rt/bgp.go
new file mode 100644
index 0000000000000000000000000000000000000000..7e71427dcf111932d199950eb3d93cedd77f296f
--- /dev/null
+++ b/rt/bgp.go
@@ -0,0 +1,143 @@
+package rt
+
+import (
+	"sync"
+
+	log "github.com/sirupsen/logrus"
+)
+
+type BGPPath struct {
+	PathIdentifier uint32
+	NextHop        uint32
+	LocalPref      uint32
+	ASPath         string
+	ASPathLen      uint16
+	Origin         uint8
+	MED            uint32
+	EBGP           bool
+	Source         uint32
+}
+
+type BGPPathManager struct {
+	paths map[BGPPath]*BGPPathCounter
+	mu    sync.Mutex
+}
+
+type BGPPathCounter struct {
+	usageCount uint64
+	path       *BGPPath
+}
+
+func NewBGPPathManager() *BGPPathManager {
+	m := &BGPPathManager{}
+	return m
+}
+
+func (m *BGPPathManager) pathExists(p BGPPath) bool {
+	if _, ok := m.paths[p]; !ok {
+		return false
+	}
+
+	return true
+}
+
+func (m *BGPPathManager) AddPath(p BGPPath) *BGPPath {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	if !m.pathExists(p) {
+		m.paths[p] = &BGPPathCounter{
+			path: &p,
+		}
+	}
+
+	m.paths[p].usageCount++
+	return m.paths[p].path
+}
+
+func (m *BGPPathManager) RemovePath(p BGPPath) {
+	m.mu.Lock()
+	defer m.mu.Unlock()
+
+	if !m.pathExists(p) {
+		log.Fatalf("Tried to remove non-existent BGPPath: %v", p)
+		return
+	}
+
+	m.paths[p].usageCount--
+	if m.paths[p].usageCount == 0 {
+		delete(m.paths, p)
+	}
+}
+
+func (r *Route) bgpPathSelection() (res []*Path) {
+	// TODO: Implement next hop lookup and compare IGP metrics
+	if len(r.paths) == 1 {
+		copy(res, r.paths)
+		return res
+	}
+
+	for _, p := range r.paths {
+		if p.Type != BGPPathType {
+			continue
+		}
+
+		if len(res) == 0 {
+			res = append(res, p)
+			continue
+		}
+
+		if res[0].BGPPath.ecmp(p.BGPPath) {
+			res = append(res, p)
+			continue
+		}
+
+		if !res[0].BGPPath.better(p.BGPPath) {
+			continue
+		}
+
+		res = []*Path{p}
+	}
+
+	return res
+}
+
+func (b *BGPPath) better(c *BGPPath) bool {
+	if c.LocalPref < b.LocalPref {
+		return false
+	}
+
+	if c.LocalPref > b.LocalPref {
+		return true
+	}
+
+	if c.ASPathLen > b.ASPathLen {
+		return false
+	}
+
+	if c.ASPathLen < b.ASPathLen {
+		return true
+	}
+
+	if c.Origin > b.Origin {
+		return false
+	}
+
+	if c.Origin < b.Origin {
+		return true
+	}
+
+	if c.MED > b.MED {
+		return false
+	}
+
+	if c.MED < b.MED {
+		return true
+	}
+
+	return false
+}
+
+func (b *BGPPath) ecmp(c *BGPPath) bool {
+	return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.Origin == c.Origin && b.MED == c.MED
+}
diff --git a/rt/lpm_test.go.dis b/rt/lpm_test.go.dis
new file mode 100644
index 0000000000000000000000000000000000000000..90f9e450ba42b376a81b239f90285aca497902e7
--- /dev/null
+++ b/rt/lpm_test.go.dis
@@ -0,0 +1,673 @@
+package rt
+
+import (
+	"testing"
+
+	"github.com/taktv6/tbgp/net"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNew(t *testing.T) {
+	l := New()
+	if l == nil {
+		t.Errorf("New() returned nil")
+	}
+}
+
+func TestRemove(t *testing.T) {
+	tests := []struct {
+		name     string
+		routes   []*Route
+		remove   []*net.Prefix
+		expected []*Route
+	}{
+		{
+			name: "Test 1",
+			routes: []*Route{
+				NewRoute(net.NewPfx(167772160, 8)), // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 9)), // 10.0.0.0
+				NewRoute(net.NewPfx(176160768, 9)), // 10.128.0.0
+			},
+			remove: []*net.Prefix{
+				net.NewPfx(167772160, 8), // 10.0.0.0
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 9)), // 10.0.0.0
+				NewRoute(net.NewPfx(176160768, 9)), // 10.128.0.0
+			},
+		},
+		{
+			name: "Test 2",
+			routes: []*Route{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0/8
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0/12
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0/10
+			},
+			remove: []*net.Prefix{
+				net.NewPfx(167772160, 7), // 10.0.0.0/7
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0/8
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0/10
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0/12
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+			},
+		},
+		{
+			name: "Test 3",
+			remove: []*net.Prefix{
+				NewRoute(net.NewPfx(167772160, 7)), // 10.0.0.0/7
+			},
+			expected: []*Route{},
+		},
+		{
+			name: "Test 4",
+			prefixes: []*net.Prefix{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0
+				NewRoute(net.NewPfx(191134592, 25)), // 11.100.123.128/25
+			},
+			remove: []*net.Prefix{
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0
+				NewRoute(net.NewPfx(191134592, 25)), // 11.100.123.128/25
+			},
+		},
+		{
+			name: "Test 5",
+			prefixes: []*net.Prefix{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0
+				NewRoute(net.NewPfx(191134592, 25)), // 11.100.123.128/25
+			},
+			remove: []*net.Prefix{
+				NewRoute(net.NewPfx(167772160, 12)), // 10.0.0.0/12
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 8)),  // 10.0.0.0
+				NewRoute(net.NewPfx(167772160, 10)), // 10.0.0.0
+				NewRoute(net.NewPfx(191134464, 24)), // 11.100.123.0/24
+				NewRoute(net.NewPfx(191134592, 25)), // 11.100.123.128/25
+			},
+		},
+	}
+
+	for _, test := range tests {
+		lpm := New()
+		for _, route := range test.routes {
+			lpm.Insert(route)
+		}
+
+		for _, pfx := range test.remove {
+			lpm.Remove(pfx)
+		}
+
+		res := lpm.Dump()
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestInsert(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefixes []*net.Prefix
+		expected *node
+	}{
+		{
+			name: "Insert first node",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8)}, // 10.0.0.0/8
+				skip: 8,
+			},
+		},
+		{
+			name: "Insert double node",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+				},
+				skip: 8,
+			},
+		},
+		{
+			name: "Insert triangle",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8), // 10.0.0.0
+				net.NewPfx(167772160, 9), // 10.0.0.0
+				net.NewPfx(176160768, 9), // 10.128.0.0
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+				},
+				skip: 8,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 9), // 10.0.0.0
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(176160768, 9), // 10.128.0.0
+					},
+				},
+			},
+		},
+		{
+			name: "Insert disjunct prefixes",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 7), // 10.0.0.0/7
+				},
+				skip:  7,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(191134464, 24), // 10.0.0.0/8
+					},
+					skip: 16,
+				},
+			},
+		},
+		{
+			name: "Insert disjunct prefixes plus one child low",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 7), // 10.0.0.0/7
+				},
+				skip:  7,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+					},
+					l: &node{
+						skip: 1,
+						route: &Route{
+							pfx: net.NewPfx(167772160, 10), // 10.0.0.0/10
+						},
+						l: &node{
+							skip: 1,
+							route: &Route{
+								pfx: net.NewPfx(167772160, 12), // 10.0.0.0
+							},
+						},
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(191134464, 24), // 10.0.0.0/8
+					},
+					skip: 16,
+				},
+			},
+		},
+		{
+			name: "Insert disjunct prefixes plus one child high",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+				net.NewPfx(191134592, 25), // 11.100.123.128/25
+			},
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 7), // 10.0.0.0/7
+				},
+				skip:  7,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+					},
+					l: &node{
+						skip: 1,
+						route: &Route{
+							pfx: net.NewPfx(167772160, 10), // 10.0.0.0/10
+						},
+						l: &node{
+							skip: 1,
+							route: &Route{
+								pfx: net.NewPfx(167772160, 12), // 10.0.0.0
+							},
+						},
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(191134464, 24), //11.100.123.0/24
+					},
+					skip: 16,
+					h: &node{
+						route: &Route{
+							pfx: net.NewPfx(191134592, 25), //11.100.123.128/25
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		l := New()
+		for _, pfx := range test.prefixes {
+			l.Insert(&Route{pfx: pfx})
+		}
+
+		assert.Equal(t, test.expected, l.root)
+	}
+}
+
+func TestLPM(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefixes []*net.Prefix
+		needle   *net.Prefix
+		expected []*net.Prefix
+	}{
+		{
+			name: "Test 1",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+			needle: net.NewPfx(167772160, 32), // 10.0.0.0/32
+			expected: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+				net.NewPfx(167772160, 12), // 10.0.0.0
+			},
+		},
+		{
+			name:     "Test 2",
+			prefixes: []*net.Prefix{},
+			needle:   net.NewPfx(167772160, 32), // 10.0.0.0/32
+			expected: nil,
+		},
+		{
+			name: "Test 3",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+			needle: net.NewPfx(167772160, 10), // 10.0.0.0/10
+			expected: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+		},
+	}
+
+	for _, test := range tests {
+		lpm := New()
+		for _, pfx := range test.prefixes {
+			lpm.Insert(&Route{pfx: pfx})
+		}
+		assert.Equal(t, test.expected, lpm.LPM(test.needle))
+	}
+}
+
+func TestGet(t *testing.T) {
+	tests := []struct {
+		name          string
+		moreSpecifics bool
+		prefixes      []*net.Prefix
+		needle        *net.Prefix
+		expected      []*net.Prefix
+	}{
+		{
+			name:          "Test 1: Search pfx and dump more specifics",
+			moreSpecifics: true,
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0/12
+				net.NewPfx(167772160, 10), // 10.0.0.0/10
+			},
+			needle: net.NewPfx(167772160, 8), // 10.0.0.0/8
+			expected: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(167772160, 10), // 10.0.0.0
+				net.NewPfx(167772160, 12), // 10.0.0.0
+			},
+		},
+		{
+			name: "Test 2: Search pfx and don't dump more specifics",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+			needle: net.NewPfx(167772160, 8), // 10.0.0.0/8
+			expected: []*net.Prefix{
+				net.NewPfx(167772160, 8), // 10.0.0.0/8
+			},
+		},
+		{
+			name:     "Test 3",
+			prefixes: []*net.Prefix{},
+			needle:   net.NewPfx(167772160, 32), // 10.0.0.0/32
+			expected: nil,
+		},
+		{
+			name: "Test 4: Get Dummy",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+			},
+			needle:   net.NewPfx(167772160, 7), // 10.0.0.0/7
+			expected: nil,
+		},
+		{
+			name: "Test 5",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0
+				net.NewPfx(167772160, 10), // 10.0.0.0
+			},
+			needle: net.NewPfx(191134464, 24), // 10.0.0.0/8
+			expected: []*net.Prefix{
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+			},
+		},
+		{
+			name: "Test 4: Get nonexistent #1",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+			},
+			needle:   net.NewPfx(167772160, 10), // 10.0.0.0/10
+			expected: nil,
+		},
+		{
+			name: "Test 4: Get nonexistent #2",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(167772160, 12), // 10.0.0.0/12
+			},
+			needle:   net.NewPfx(167772160, 10), // 10.0.0.0/10
+			expected: nil,
+		},
+	}
+
+	for _, test := range tests {
+		lpm := New()
+		for _, pfx := range test.prefixes {
+			lpm.Insert(&Route{pfx: pfx})
+		}
+		p := lpm.Get(test.needle, test.moreSpecifics)
+
+		if p == nil {
+			if test.expected != nil {
+				t.Errorf("Unexpected nil result for test %q", test.name)
+			}
+			continue
+		}
+
+		assert.Equal(t, test.expected, p)
+	}
+}
+
+func TestNewSuperNode(t *testing.T) {
+	tests := []struct {
+		name     string
+		a        *net.Prefix
+		b        *net.Prefix
+		expected *node
+	}{
+		{
+			name: "Test 1",
+			a:    net.NewPfx(167772160, 8),  // 10.0.0.0/8
+			b:    net.NewPfx(191134464, 24), // 11.100.123.0/24
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 7), // 10.0.0.0/7
+				},
+				skip:  7,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 8), // 10.0.0.0/8
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(191134464, 24), //11.100.123.0/24
+					},
+					skip: 16,
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		n := newNode(&Route{pfx: test.a}, test.a.Pfxlen(), false)
+		n = n.newSuperNode(&Route{pfx: test.b})
+		assert.Equal(t, test.expected, n)
+	}
+}
+
+func TestDumpPfxs(t *testing.T) {
+	tests := []struct {
+		name     string
+		prefixes []*net.Prefix
+		expected []*net.Prefix
+	}{
+
+		{
+			name:     "Test 1: Empty node",
+			expected: nil,
+		},
+		{
+			name: "Test 2: ",
+			prefixes: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+				net.NewPfx(167772160, 12), // 10.0.0.0/12
+				net.NewPfx(167772160, 10), // 10.0.0.0/10
+			},
+			expected: []*net.Prefix{
+				net.NewPfx(167772160, 8),  // 10.0.0.0/8
+				net.NewPfx(167772160, 10), // 10.0.0.0/10
+				net.NewPfx(167772160, 12), // 10.0.0.0/12
+				net.NewPfx(191134464, 24), // 11.100.123.0/24
+			},
+		},
+	}
+
+	for _, test := range tests {
+		lpm := New()
+		for _, pfx := range test.prefixes {
+			lpm.Insert(&Route{pfx: pfx})
+		}
+
+		res := make([]*Route, 0)
+		r := lpm.root.dumpPfxs(res)
+		assert.Equal(t, test.expected, r)
+	}
+}
+
+func TestGetBitUint32(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint32
+		offset   uint8
+		expected bool
+	}{
+		{
+			name:     "test 1",
+			input:    167772160, // 10.0.0.0
+			offset:   8,
+			expected: false,
+		},
+		{
+			name:     "test 2",
+			input:    184549376, // 11.0.0.0
+			offset:   8,
+			expected: true,
+		},
+	}
+
+	for _, test := range tests {
+		b := getBitUint32(test.input, test.offset)
+		if b != test.expected {
+			t.Errorf("%s: Unexpected failure: Bit %d of %d is %v. Expected %v", test.name, test.offset, test.input, b, test.expected)
+		}
+	}
+}
+
+func TestInsertChildren(t *testing.T) {
+	tests := []struct {
+		name     string
+		base     *net.Prefix
+		old      *net.Prefix
+		new      *net.Prefix
+		expected *node
+	}{
+		{
+			name: "Test 1",
+			base: net.NewPfx(167772160, 8), //10.0.0.0/8
+			old:  net.NewPfx(167772160, 9), //10.0.0.0/9
+			new:  net.NewPfx(176160768, 9), //10.128.0.0/9
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8),
+				},
+				skip:  8,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 9),
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(176160768, 9),
+					},
+				},
+			},
+		},
+		{
+			name: "Test 2",
+			base: net.NewPfx(167772160, 8), //10.0.0.0/8
+			old:  net.NewPfx(176160768, 9), //10.128.0.0/9
+			new:  net.NewPfx(167772160, 9), //10.0.0.0/9
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8),
+				},
+				skip:  8,
+				dummy: true,
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 9),
+					},
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(176160768, 9),
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		n := newNode(&Route{pfx: test.base}, test.base.Pfxlen(), true)
+		old := newNode(&Route{pfx: test.old}, test.old.Pfxlen(), false)
+		n.insertChildren(old, &Route{pfx: test.new})
+		assert.Equal(t, test.expected, n)
+	}
+}
+
+func TestInsertBefore(t *testing.T) {
+	tests := []struct {
+		name     string
+		a        *net.Prefix
+		b        *net.Prefix
+		expected *node
+	}{
+		{
+			name: "Test 1",
+			a:    net.NewPfx(167772160, 10), // 10.0.0.0
+			b:    net.NewPfx(167772160, 8),  // 10.0.0.0
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 8), // 10.0.0.0,
+				},
+				l: &node{
+					route: &Route{
+						pfx: net.NewPfx(167772160, 10), // 10.0.0.0
+					},
+					skip: 1,
+				},
+				skip: 8,
+			},
+		},
+		{
+			name: "Test 2",
+			a:    net.NewPfx(184549376, 8), // 11.0.0.0/8
+			b:    net.NewPfx(167772160, 7), // 10.0.0.0/7
+			expected: &node{
+				route: &Route{
+					pfx: net.NewPfx(167772160, 7), // 10.0.0.0,
+				},
+				h: &node{
+					route: &Route{
+						pfx: net.NewPfx(184549376, 8), // 10.0.0.0
+					},
+					skip: 0,
+				},
+				skip: 7,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		n := newNode(&Route{pfx: test.a}, test.a.Pfxlen(), false)
+		n = n.insertBefore(&Route{pfx: test.b}, test.b.Pfxlen())
+		assert.Equal(t, test.expected, n)
+	}
+}
diff --git a/rt/route.go b/rt/route.go
new file mode 100644
index 0000000000000000000000000000000000000000..42dd416244a2b46f7080fbc10ea7852f3b5f7760
--- /dev/null
+++ b/rt/route.go
@@ -0,0 +1,125 @@
+package rt
+
+import (
+	net "github.com/bio-routing/bio-rd/net"
+)
+
+// Path Types
+const StaticPathType = 1
+const BGPPathType = 2
+const OSPFPathType = 3
+const ISISPathType = 4
+
+type Path struct {
+	Type       uint8
+	StaticPath *StaticPath
+	BGPPath    *BGPPath
+}
+
+type Route struct {
+	pfx         *net.Prefix
+	activePaths []*Path
+	paths       []*Path
+}
+
+func NewRoute(pfx *net.Prefix, paths []*Path) *Route {
+	return &Route{
+		pfx:         pfx,
+		activePaths: make([]*Path, 0),
+		paths:       paths,
+	}
+}
+
+func (r *Route) Pfxlen() uint8 {
+	return r.pfx.Pfxlen()
+}
+
+func (r *Route) Prefix() *net.Prefix {
+	return r.pfx
+}
+
+func (r *Route) Remove(rm *Route) (final bool) {
+	for _, del := range rm.paths {
+		r.paths = removePath(r.paths, del)
+	}
+
+	return len(r.paths) == 0
+}
+
+func removePath(paths []*Path, remove *Path) []*Path {
+	i := -1
+	for j := range paths {
+		if paths[j].Equal(remove) {
+			i = j
+			break
+		}
+	}
+
+	if i < 0 {
+		return paths
+	}
+
+	copy(paths[i:], paths[i+1:])
+	return paths[:len(paths)-1]
+}
+
+func (p *Path) Equal(q *Path) bool {
+	if p == nil || q == nil {
+		return false
+	}
+
+	if p.Type != q.Type {
+		return false
+	}
+
+	switch p.Type {
+	case BGPPathType:
+		if *p.BGPPath != *q.BGPPath {
+			return false
+		}
+	}
+
+	return true
+}
+
+func (r *Route) AddPath(p *Path) {
+	r.paths = append(r.paths, p)
+	r.bestPaths()
+}
+
+func (r *Route) AddPaths(paths []*Path) {
+	for _, p := range paths {
+		r.paths = append(r.paths, p)
+	}
+	r.bestPaths()
+}
+
+func (r *Route) bestPaths() {
+	var best []*Path
+	protocol := getBestProtocol(r.paths)
+
+	switch protocol {
+	case StaticPathType:
+		best = r.staticPathSelection()
+	case BGPPathType:
+		best = r.bgpPathSelection()
+	}
+
+	r.activePaths = best
+}
+
+func getBestProtocol(paths []*Path) uint8 {
+	best := uint8(0)
+	for _, p := range paths {
+		if best == 0 {
+			best = p.Type
+			continue
+		}
+
+		if p.Type > best {
+			best = p.Type
+		}
+	}
+
+	return best
+}
diff --git a/rt/route_test.go b/rt/route_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..d4633694903eae24d79a35a0803c4b07edfa5073
--- /dev/null
+++ b/rt/route_test.go
@@ -0,0 +1,369 @@
+package rt
+
+import (
+	"testing"
+
+	net "github.com/bio-routing/bio-rd/net"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewRoute(t *testing.T) {
+	tests := []struct {
+		name     string
+		pfx      *net.Prefix
+		paths    []*Path
+		expected *Route
+	}{
+		{
+			name: "Test #1",
+			pfx:  net.NewPfx(158798889, 24),
+			paths: []*Path{
+				{
+					Type: 2,
+					StaticPath: &StaticPath{
+						NextHop: 56963289,
+					},
+				},
+			},
+			expected: &Route{
+				pfx:         net.NewPfx(158798889, 24),
+				activePaths: make([]*Path, 0),
+				paths: []*Path{
+					{
+						Type: 2,
+						StaticPath: &StaticPath{
+							NextHop: 56963289,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res := NewRoute(test.pfx, test.paths)
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestPfxlen(t *testing.T) {
+	tests := []struct {
+		name     string
+		pfx      *net.Prefix
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			pfx:      net.NewPfx(158798889, 24),
+			expected: 24,
+		},
+	}
+
+	for _, test := range tests {
+		r := NewRoute(test.pfx, nil)
+		res := r.Pfxlen()
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestPrefix(t *testing.T) {
+	tests := []struct {
+		name     string
+		pfx      *net.Prefix
+		expected *net.Prefix
+	}{
+		{
+			name:     "Test #1",
+			pfx:      net.NewPfx(158798889, 24),
+			expected: net.NewPfx(158798889, 24),
+		},
+	}
+
+	for _, test := range tests {
+		r := NewRoute(test.pfx, nil)
+		res := r.Prefix()
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestRouteRemovePath(t *testing.T) {
+	tests := []struct {
+		name     string
+		paths    []*Path
+		remove   *Path
+		expected []*Path
+	}{
+		{
+			name: "Remove middle",
+			paths: []*Path{
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 100,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 200,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 300,
+					},
+				},
+			},
+			remove: &Path{
+				Type: BGPPathType,
+				BGPPath: &BGPPath{
+					LocalPref: 200,
+				},
+			},
+			expected: []*Path{
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 100,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 300,
+					},
+				},
+			},
+		},
+		{
+			name: "Remove non-existent",
+			paths: []*Path{
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 10,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 20,
+					},
+				},
+			},
+			remove: &Path{
+				Type: BGPPathType,
+				BGPPath: &BGPPath{
+					LocalPref: 50,
+				},
+			},
+			expected: []*Path{
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 10,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 20,
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res := removePath(test.paths, test.remove)
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestEqual(t *testing.T) {
+	tests := []struct {
+		name     string
+		pathA    *Path
+		pathB    *Path
+		expected bool
+	}{
+		{
+			name: "Unequal types",
+			pathA: &Path{
+				Type: 1,
+			},
+			pathB: &Path{
+				Type: 2,
+			},
+			expected: false,
+		},
+		{
+			name: "Unequal attributes",
+			pathA: &Path{
+				Type: 2,
+				BGPPath: &BGPPath{
+					LocalPref: 100,
+				},
+			},
+			pathB: &Path{
+				Type: 2,
+				BGPPath: &BGPPath{
+					LocalPref: 200,
+				},
+			},
+			expected: false,
+		},
+		{
+			name: "Equal",
+			pathA: &Path{
+				Type: 2,
+				BGPPath: &BGPPath{
+					LocalPref: 100,
+				},
+			},
+			pathB: &Path{
+				Type: 2,
+				BGPPath: &BGPPath{
+					LocalPref: 100,
+				},
+			},
+			expected: true,
+		},
+	}
+
+	for _, test := range tests {
+		res := test.pathA.Equal(test.pathB)
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestAddPath(t *testing.T) {
+	tests := []struct {
+		name     string
+		route    *Route
+		new      *Path
+		expected *Route
+	}{
+		{
+			name: "Add a new best path",
+			route: &Route{
+				paths: []*Path{
+					{
+						Type: 2,
+						BGPPath: &BGPPath{
+							LocalPref: 100,
+						},
+					},
+				},
+			},
+			new: &Path{
+				Type: 2,
+				BGPPath: &BGPPath{
+					LocalPref: 200,
+				},
+			},
+			expected: &Route{
+				activePaths: []*Path{
+					{
+						Type: 2,
+						BGPPath: &BGPPath{
+							LocalPref: 200,
+						},
+					},
+				},
+				paths: []*Path{
+					{
+						Type: 2,
+						BGPPath: &BGPPath{
+							LocalPref: 100,
+						},
+					},
+					{
+						Type: 2,
+						BGPPath: &BGPPath{
+							LocalPref: 200,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		test.route.AddPath(test.new)
+		assert.Equal(t, test.expected, test.route)
+	}
+}
+
+func TestAddPaths(t *testing.T) {
+	tests := []struct {
+		name     string
+		route    *Route
+		new      []*Path
+		expected *Route
+	}{
+		{
+			name: "Add 2 new paths including a new best path",
+			route: &Route{
+				paths: []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 100,
+						},
+					},
+				},
+			},
+			new: []*Path{
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 200,
+					},
+				},
+				{
+					Type: BGPPathType,
+					BGPPath: &BGPPath{
+						LocalPref: 50,
+					},
+				},
+			},
+			expected: &Route{
+				activePaths: []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 200,
+						},
+					},
+				},
+				paths: []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 100,
+						},
+					},
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 200,
+						},
+					},
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 50,
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		test.route.AddPaths(test.new)
+		assert.Equal(t, test.expected, test.route)
+	}
+}
diff --git a/rt/routing_table.go b/rt/routing_table.go
new file mode 100644
index 0000000000000000000000000000000000000000..0ca9812a3a681890e346d7664eaea8e8bf7d6350
--- /dev/null
+++ b/rt/routing_table.go
@@ -0,0 +1,312 @@
+package rt
+
+import (
+	"github.com/bio-routing/bio-rd/net"
+)
+
+type LPM struct {
+	root  *node
+	nodes uint64
+}
+
+type node struct {
+	skip  uint8
+	dummy bool
+	route *Route
+	l     *node
+	h     *node
+}
+
+// New creates a new empty LPM
+func New() *LPM {
+	return &LPM{}
+}
+
+func newNode(route *Route, skip uint8, dummy bool) *node {
+	n := &node{
+		route: route,
+		skip:  skip,
+		dummy: dummy,
+	}
+	return n
+}
+
+// LPM performs a longest prefix match for pfx on lpm
+func (lpm *LPM) LPM(pfx *net.Prefix) (res []*Route) {
+	if lpm.root == nil {
+		return nil
+	}
+
+	lpm.root.lpm(pfx, &res)
+	return res
+}
+
+// RemovePath removes a path from the trie
+func (lpm *LPM) RemovePath(route *Route) {
+	lpm.root.removePath(route)
+}
+
+func (lpm *LPM) RemovePfx(pfx *net.Prefix) {
+	lpm.root.removePfx(pfx)
+}
+
+// Get get's prefix pfx from the LPM
+func (lpm *LPM) Get(pfx *net.Prefix, moreSpecifics bool) (res []*Route) {
+	if lpm.root == nil {
+		return nil
+	}
+
+	node := lpm.root.get(pfx)
+	if moreSpecifics {
+		return node.dumpPfxs(res)
+	}
+
+	if node == nil {
+		return nil
+	}
+
+	return []*Route{
+		node.route,
+	}
+}
+
+// Insert inserts a route into the LPM
+func (lpm *LPM) Insert(route *Route) {
+	if lpm.root == nil {
+		lpm.root = newNode(route, route.Pfxlen(), false)
+		return
+	}
+
+	lpm.root = lpm.root.insert(route)
+}
+
+func (n *node) removePath(route *Route) {
+	if n == nil {
+		return
+	}
+
+	if *n.route.Prefix() == *route.Prefix() {
+		if n.dummy {
+			return
+		}
+
+		if n.route.Remove(route) {
+			// FIXME: Can this node actually be removed from the trie entirely?
+			n.dummy = true
+		}
+
+		return
+	}
+
+	b := getBitUint32(route.Prefix().Addr(), n.route.Pfxlen()+1)
+	if !b {
+		n.l.removePath(route)
+		return
+	}
+	n.h.removePath(route)
+	return
+}
+
+func (n *node) removePfx(pfx *net.Prefix) {
+	if n == nil {
+		return
+	}
+
+	if *n.route.Prefix() == *pfx {
+		if n.dummy {
+			return
+		}
+
+		n.dummy = true
+
+		return
+	}
+
+	b := getBitUint32(pfx.Addr(), n.route.Pfxlen()+1)
+	if !b {
+		n.l.removePfx(pfx)
+		return
+	}
+	n.h.removePfx(pfx)
+	return
+}
+
+func (n *node) lpm(needle *net.Prefix, res *[]*Route) {
+	if n == nil {
+		return
+	}
+
+	if *n.route.Prefix() == *needle && !n.dummy {
+		*res = append(*res, n.route)
+		return
+	}
+
+	if !n.route.Prefix().Contains(needle) {
+		return
+	}
+
+	if !n.dummy {
+		*res = append(*res, n.route)
+	}
+	n.l.lpm(needle, res)
+	n.h.lpm(needle, res)
+}
+
+func (n *node) dumpPfxs(res []*Route) []*Route {
+	if n == nil {
+		return nil
+	}
+
+	if !n.dummy {
+		res = append(res, n.route)
+	}
+
+	if n.l != nil {
+		res = n.l.dumpPfxs(res)
+	}
+
+	if n.h != nil {
+		res = n.h.dumpPfxs(res)
+	}
+
+	return res
+}
+
+func (n *node) get(pfx *net.Prefix) *node {
+	if n == nil {
+		return nil
+	}
+
+	if *n.route.Prefix() == *pfx {
+		if n.dummy {
+			return nil
+		}
+		return n
+	}
+
+	if n.route.Pfxlen() > pfx.Pfxlen() {
+		return nil
+	}
+
+	b := getBitUint32(pfx.Addr(), n.route.Pfxlen()+1)
+	if !b {
+		return n.l.get(pfx)
+	}
+	return n.h.get(pfx)
+}
+
+func (n *node) insert(route *Route) *node {
+	if *n.route.Prefix() == *route.Prefix() {
+		n.route.AddPaths(route.paths)
+		n.dummy = false
+		return n
+	}
+
+	// is pfx NOT a subnet of this node?
+	if !n.route.Prefix().Contains(route.Prefix()) {
+		if route.Prefix().Contains(n.route.Prefix()) {
+			return n.insertBefore(route, n.route.Pfxlen()-n.skip-1)
+		}
+
+		return n.newSuperNode(route)
+	}
+
+	// pfx is a subnet of this node
+	b := getBitUint32(route.Prefix().Addr(), n.route.Pfxlen()+1)
+	if !b {
+		return n.insertLow(route, n.route.Prefix().Pfxlen())
+	}
+	return n.insertHigh(route, n.route.Pfxlen())
+}
+
+func (n *node) insertLow(route *Route, parentPfxLen uint8) *node {
+	if n.l == nil {
+		n.l = newNode(route, route.Pfxlen()-parentPfxLen-1, false)
+		return n
+	}
+	n.l = n.l.insert(route)
+	return n
+}
+
+func (n *node) insertHigh(route *Route, parentPfxLen uint8) *node {
+	if n.h == nil {
+		n.h = newNode(route, route.Pfxlen()-parentPfxLen-1, false)
+		return n
+	}
+	n.h = n.h.insert(route)
+	return n
+}
+
+func (n *node) newSuperNode(route *Route) *node {
+	superNet := route.Prefix().GetSupernet(n.route.Prefix())
+
+	pfxLenDiff := n.route.Pfxlen() - superNet.Pfxlen()
+	skip := n.skip - pfxLenDiff
+
+	pseudoNode := newNode(NewRoute(superNet, nil), skip, true)
+	pseudoNode.insertChildren(n, route)
+	return pseudoNode
+}
+
+func (n *node) insertChildren(old *node, new *Route) {
+	// Place the old node
+	b := getBitUint32(old.route.Prefix().Addr(), n.route.Pfxlen()+1)
+	if !b {
+		n.l = old
+		n.l.skip = old.route.Pfxlen() - n.route.Pfxlen() - 1
+	} else {
+		n.h = old
+		n.h.skip = old.route.Pfxlen() - n.route.Pfxlen() - 1
+	}
+
+	// Place the new Prefix
+	newNode := newNode(new, new.Pfxlen()-n.route.Pfxlen()-1, false)
+	b = getBitUint32(new.Prefix().Addr(), n.route.Pfxlen()+1)
+	if !b {
+		n.l = newNode
+	} else {
+		n.h = newNode
+	}
+}
+
+func (n *node) insertBefore(route *Route, parentPfxLen uint8) *node {
+	tmp := n
+
+	pfxLenDiff := n.route.Pfxlen() - route.Pfxlen()
+	skip := n.skip - pfxLenDiff
+	new := newNode(route, skip, false)
+
+	b := getBitUint32(route.Prefix().Addr(), parentPfxLen)
+	if !b {
+		new.l = tmp
+		new.l.skip = tmp.route.Pfxlen() - route.Pfxlen() - 1
+	} else {
+		new.h = tmp
+		new.h.skip = tmp.route.Pfxlen() - route.Pfxlen() - 1
+	}
+
+	return new
+}
+
+func (lpm *LPM) Dump() []*Route {
+	res := make([]*Route, 0)
+	return lpm.root.dump(res)
+}
+
+func (n *node) dump(res []*Route) []*Route {
+	if n == nil {
+		return res
+	}
+
+	if !n.dummy {
+		res = append(res, n.route)
+	}
+
+	res = n.l.dump(res)
+	res = n.h.dump(res)
+	return res
+}
+
+func getBitUint32(x uint32, pos uint8) bool {
+	return ((x) & (1 << (32 - pos))) != 0
+}
diff --git a/rt/routing_table_test.go b/rt/routing_table_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..a1de4f03d372cef1dcb7af517f20b27f350547f7
--- /dev/null
+++ b/rt/routing_table_test.go
@@ -0,0 +1,152 @@
+package rt
+
+import (
+	"testing"
+
+	net "github.com/bio-routing/bio-rd/net"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNew(t *testing.T) {
+	l := New()
+	if l == nil {
+		t.Errorf("New() returned nil")
+	}
+}
+
+func TestRemovePath(t *testing.T) {
+	tests := []struct {
+		name     string
+		routes   []*Route
+		remove   []*Route
+		expected []*Route
+	}{
+		{
+			name: "Remove a path that is the only one for a prefix",
+			routes: []*Route{
+				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}),
+				NewRoute(net.NewPfx(167772160, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.0.0.0/9
+				NewRoute(net.NewPfx(176160768, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.128.0.0/9
+			},
+			remove: []*Route{
+				NewRoute(net.NewPfx(167772160, 8), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.0.0.0
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.0.0.0
+				NewRoute(net.NewPfx(176160768, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.128.0.0
+			},
+		},
+		{
+			name: "Remove a path that is one of two for a prefix",
+			routes: []*Route{
+				NewRoute(net.NewPfx(167772160, 8), []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 1000,
+						},
+					},
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 2000,
+						},
+					},
+				}), // 10.0.0.0/8
+				NewRoute(net.NewPfx(167772160, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.0.0.0/9
+				NewRoute(net.NewPfx(176160768, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.128.0.0/9
+			},
+			remove: []*Route{
+				NewRoute(net.NewPfx(167772160, 8), []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 1000,
+						},
+					},
+				}), // 10.0.0.0
+			},
+			expected: []*Route{
+				NewRoute(net.NewPfx(167772160, 8), []*Path{
+					{
+						Type: BGPPathType,
+						BGPPath: &BGPPath{
+							LocalPref: 2000,
+						},
+					},
+				}), // 10.0.0.0/8
+				NewRoute(net.NewPfx(167772160, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.0.0.0/9
+				NewRoute(net.NewPfx(176160768, 9), []*Path{
+					{
+						Type:    BGPPathType,
+						BGPPath: &BGPPath{},
+					},
+				}), // 10.128.0.0/9
+			},
+		},
+	}
+
+	for _, test := range tests {
+		lpm := New()
+		for _, route := range test.routes {
+			lpm.Insert(route)
+		}
+
+		for _, route := range test.remove {
+			lpm.RemovePath(route)
+		}
+
+		res := lpm.Dump()
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func strAddr(s string) uint32 {
+	ret, _ := net.StrToAddr(s)
+	return ret
+}
diff --git a/rt/static.go b/rt/static.go
new file mode 100644
index 0000000000000000000000000000000000000000..72720a6548427ce7d0a1d88fbd9039731f96698e
--- /dev/null
+++ b/rt/static.go
@@ -0,0 +1,22 @@
+package rt
+
+type StaticPath struct {
+	NextHop uint32
+}
+
+func (r *Route) staticPathSelection() (res []*Path) {
+	if len(r.paths) == 1 {
+		copy(res, r.paths)
+		return res
+	}
+
+	for _, p := range r.paths {
+		if p.Type != StaticPathType {
+			continue
+		}
+
+		res = append(res, p)
+	}
+
+	return
+}