diff --git a/main.go b/main.go
index 30aaa128fec913ee952a781a0a343f4635a71bf1..78171d7c20df8a77c4cdb95553591b4b19381c92 100644
--- a/main.go
+++ b/main.go
@@ -4,18 +4,19 @@ import (
 	"fmt"
 	"net"
 	"sync"
+	"time"
 
 	"github.com/sirupsen/logrus"
 
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/server"
-	"github.com/bio-routing/bio-rd/rt"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 )
 
 func main() {
 	fmt.Printf("This is a BGP speaker\n")
 
-	VRF := rt.New(true)
+	rib := locRIB.New()
 	b := server.NewBgpServer()
 
 	err := b.Start(&config.Global{
@@ -28,26 +29,35 @@ func main() {
 	b.AddPeer(config.Peer{
 		AdminEnabled: true,
 		LocalAS:      65200,
-		PeerAS:       65100,
-		PeerAddress:  net.IP([]byte{169, 254, 100, 0}),
-		LocalAddress: net.IP([]byte{169, 254, 100, 1}),
+		PeerAS:       65300,
+		PeerAddress:  net.IP([]byte{169, 254, 200, 1}),
+		LocalAddress: net.IP([]byte{169, 254, 200, 0}),
 		HoldTimer:    90,
 		KeepAlive:    30,
 		Passive:      true,
 		RouterID:     b.RouterID(),
-	}, VRF)
+	}, rib)
+
+	time.Sleep(time.Second * 30)
 
 	b.AddPeer(config.Peer{
 		AdminEnabled: true,
 		LocalAS:      65200,
-		PeerAS:       65300,
-		PeerAddress:  net.IP([]byte{169, 254, 200, 1}),
-		LocalAddress: net.IP([]byte{169, 254, 200, 0}),
+		PeerAS:       65100,
+		PeerAddress:  net.IP([]byte{169, 254, 100, 0}),
+		LocalAddress: net.IP([]byte{169, 254, 100, 1}),
 		HoldTimer:    90,
 		KeepAlive:    30,
 		Passive:      true,
 		RouterID:     b.RouterID(),
-	}, VRF)
+	}, rib)
+
+	go func() {
+		for {
+			fmt.Print(rib.Print())
+			time.Sleep(time.Second * 10)
+		}
+	}()
 
 	var wg sync.WaitGroup
 	wg.Add(1)
diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go
index be4f30dc5890e9abca69a4822a3e7d6187a30a0c..ba1d3d32206fe90680798ec1bf7338a9ee6fee22 100644
--- a/protocols/bgp/packet/bgp.go
+++ b/protocols/bgp/packet/bgp.go
@@ -1,8 +1,9 @@
 package packet
 
 const (
-	OctetLen    = 8
-	BGP4Version = 4
+	OctetLen       = 8
+	MaxASNsSegment = 255
+	BGP4Version    = 4
 
 	MarkerLen  = 16
 	HeaderLen  = 19
@@ -130,7 +131,7 @@ type PathAttribute struct {
 }
 
 type NLRI struct {
-	IP     interface{}
+	IP     uint32
 	Pfxlen uint8
 	Next   *NLRI
 }
diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go
index 42c7a65e07af14b46719ef8630d42b79443184cd..05fecbff1a4ccf8441306ae340d88ed170cdb409 100644
--- a/protocols/bgp/packet/nlri.go
+++ b/protocols/bgp/packet/nlri.go
@@ -57,12 +57,12 @@ func decodeNLRI(buf *bytes.Buffer) (*NLRI, uint8, error) {
 			addr[i] = 0
 		}
 	}
-	nlri.IP = addr
+	nlri.IP = fourBytesToUint32(addr)
 	return nlri, toCopy + 1, nil
 }
 
 func (n *NLRI) serialize(buf *bytes.Buffer) uint8 {
-	a := convert.Uint32Byte(n.IP.(uint32))
+	a := convert.Uint32Byte(n.IP)
 
 	addr := [4]byte{a[0], a[1], a[2], a[3]}
 	nBytes := bytesInAddr(n.Pfxlen)
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 50c0cdb5e49d0ee0c3a4225e30ecfe9d8814c1f1..c305ec27a45b899cad0b9aeeba44a23d690d412f 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+	"strconv"
+	"strings"
 
 	"github.com/taktv6/tflow2/convert"
 )
@@ -156,7 +158,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
 		return fmt.Errorf("Unable to read next hop: buf.Read read %d bytes", n)
 	}
 
-	pa.Value = addr
+	pa.Value = fourBytesToUint32(addr)
 	p += 4
 
 	return dumpNBytes(buf, pa.Length-p)
@@ -354,8 +356,8 @@ func (pa *PathAttribute) serializeNextHop(buf *bytes.Buffer) uint8 {
 	buf.WriteByte(NextHopAttr)
 	length := uint8(4)
 	buf.WriteByte(length)
-	addr := pa.Value.([4]byte)
-	buf.Write(addr[:])
+	addr := pa.Value.(uint32)
+	buf.Write(convert.Uint32Byte(addr))
 	return 7
 }
 
@@ -402,3 +404,96 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 {
 	buf.Write(convert.Uint16Byte(pa.Value.(uint16)))
 	return 5
 }
+
+/*func (pa *PathAttribute) PrependASPath(prepend []uint32) {
+	if pa.TypeCode != ASPathAttr {
+		return
+	}
+
+	asPath := pa.Value.(ASPath)
+	asPathSegementCount := len(asPath)
+	currentSegment := asPathSegementCount - 1
+
+	newSegmentNeeded := false
+	if asPath[asPathSegementCount-1].Type == ASSequence {
+		newSegmentNeeded = true
+	} else {
+		if len(asPath[asPathSegementCount-1].ASNs) >= MaxASNsSegment {
+			newSegmentNeeded = true
+		}
+	}
+
+	for _, asn := range prepend {
+		if newSegmentNeeded {
+			segment := ASPathSegment{
+				Type: ASSequence,
+				ASNs: make([]uint32, 0),
+			},
+		}
+
+		asPath[currentSegment].ASNs = append(asPath[currentSegment].ASNs, asn)
+		if len(asPath[asPathSegementCount-1].ASNs) >= MaxASNsSegment {
+			newSegmentNeeded = true
+		}
+	}
+
+}*/
+
+// ParseASPathStr converts an AS path from string representation info an PathAttribute object
+func ParseASPathStr(asPathString string) (*PathAttribute, error) {
+	asPath := ASPath{}
+
+	currentType := ASSequence
+	newSegmentNeeded := true
+	currentSegment := -1
+	for _, asn := range strings.Split(asPathString, " ") {
+		if isBeginOfASSet(asn) {
+			currentType = ASSet
+			newSegmentNeeded = true
+			asn = strings.Replace(asn, "(", "", 1)
+		}
+
+		if newSegmentNeeded {
+			seg := ASPathSegment{
+				Type: uint8(currentType),
+				ASNs: make([]uint32, 0),
+			}
+			asPath = append(asPath, seg)
+			currentSegment++
+			newSegmentNeeded = false
+		}
+
+		if isEndOfASSset(asn) {
+			currentType = ASSequence
+			newSegmentNeeded = true
+			asn = strings.Replace(asn, ")", "", 1)
+		}
+
+		numericASN, err := strconv.Atoi(asn)
+		if err != nil {
+			return nil, fmt.Errorf("Unable to convert ASN: %v", err)
+		}
+		asPath[currentSegment].ASNs = append(asPath[currentSegment].ASNs, uint32(numericASN))
+
+		if len(asPath[currentSegment].ASNs) == MaxASNsSegment {
+			newSegmentNeeded = true
+		}
+	}
+
+	return &PathAttribute{
+		TypeCode: ASPathAttr,
+		Value:    asPath,
+	}, nil
+}
+
+func isBeginOfASSet(asPathPart string) bool {
+	return strings.Contains(asPathPart, "(")
+}
+
+func isEndOfASSset(asPathPart string) bool {
+	return strings.Contains(asPathPart, ")")
+}
+
+func fourBytesToUint32(address [4]byte) uint32 {
+	return uint32(address[0])<<24 + uint32(address[1])<<16 + uint32(address[2])<<8 + uint32(address[3])
+}
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index 247028cb85f8e9a350e929baa10b5a010e40731f..140752e5a6df98fbb3430e2a31c3b0b728ecc9cf 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -1291,3 +1291,122 @@ func TestSerialize(t *testing.T) {
 		assert.Equal(t, test.expected, res)
 	}
 }
+
+func TestParseASPathStr(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    string
+		wantFail bool
+		expected *PathAttribute
+	}{
+		{
+			name:     "Simple AS_SEQUENCE",
+			input:    "3320 15169",
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value: ASPath{
+					ASPathSegment{
+						Type: ASSequence,
+						ASNs: []uint32{3320, 15169},
+					},
+				},
+			},
+		},
+		{
+			name:     "AS_SEQUENCE with more than 255 elements",
+			input:    "123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123",
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value: ASPath{
+					ASPathSegment{
+						Type: ASSequence,
+						ASNs: []uint32{123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123},
+					},
+					ASPathSegment{
+						Type: ASSequence,
+						ASNs: []uint32{123, 123, 123, 123, 123},
+					},
+				},
+			},
+		},
+		{
+			name:     "AS_SET only",
+			input:    "(3320 201701 15169)",
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value: ASPath{
+					ASPathSegment{
+						Type: ASSet,
+						ASNs: []uint32{3320, 201701, 15169},
+					},
+				},
+			},
+		},
+		{
+			name:     "Mixed AS Path",
+			input:    "199714 51324 (3320 201701 15169)",
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value: ASPath{
+					ASPathSegment{
+						Type: ASSequence,
+						ASNs: []uint32{199714, 51324},
+					},
+					ASPathSegment{
+						Type: ASSet,
+						ASNs: []uint32{3320, 201701, 15169},
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res, err := ParseASPathStr(test.input)
+		if err != nil {
+			if test.wantFail {
+				continue
+			}
+
+			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
+			continue
+		}
+
+		if test.wantFail {
+			t.Errorf("Unexpected success for test %q", test.name)
+			continue
+		}
+
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestFourBytesToUint32(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    [4]byte
+		expected uint32
+	}{
+		{
+			name:     "Test #1",
+			input:    [4]byte{0, 0, 0, 200},
+			expected: 200,
+		},
+		{
+			name:     "Test #2",
+			input:    [4]byte{1, 0, 0, 200},
+			expected: 16777416,
+		},
+	}
+
+	for _, test := range tests {
+		res := fourBytesToUint32(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: Got: %d Want: %d", test.name, res, test.expected)
+		}
+	}
+}
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index a65d957040feeb969c50c5b94ef08c31fc937c7d..721c7fafaac61add736fc2bb6a147fd0fa984164 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -7,12 +7,16 @@ import (
 	"net"
 	"time"
 
+	"github.com/bio-routing/bio-rd/routingtable"
+
 	"github.com/bio-routing/bio-rd/config"
 	tnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/rt"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/bio-routing/bio-rd/routingtable/adjRIBIn"
+	"github.com/bio-routing/bio-rd/routingtable/adjRIBOut"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 	log "github.com/sirupsen/logrus"
-	"github.com/taktv6/tflow2/convert"
 	tomb "gopkg.in/tomb.v2"
 )
 
@@ -83,9 +87,9 @@ type FSM struct {
 	msgRecvFailCh chan msgRecvErr
 	stopMsgRecvCh chan struct{}
 
-	adjRIBIn     *rt.RT
-	adjRIBOut    *rt.RT
-	vrf          *rt.RT
+	adjRIBIn     *adjRIBIn.AdjRIBIn
+	adjRIBOut    *adjRIBOut.AdjRIBOut
+	rib          *locRIB.LocRIB
 	updateSender *UpdateSender
 }
 
@@ -99,7 +103,7 @@ type msgRecvErr struct {
 	con *net.TCPConn
 }
 
-func NewFSM(c config.Peer, vrf *rt.RT) *FSM {
+func NewFSM(c config.Peer, rib *locRIB.LocRIB) *FSM {
 	fsm := &FSM{
 		state:             Idle,
 		passive:           true,
@@ -124,7 +128,7 @@ func NewFSM(c config.Peer, vrf *rt.RT) *FSM {
 		conCh:    make(chan *net.TCPConn),
 		conErrCh: make(chan error), initiateCon: make(chan struct{}),
 
-		vrf: vrf,
+		rib: rib,
 	}
 
 	fsm.updateSender = newUpdateSender(fsm)
@@ -208,7 +212,7 @@ func (fsm *FSM) main() error {
 
 func (fsm *FSM) idle() int {
 	if fsm.adjRIBOut != nil {
-		fsm.vrf.Unregister(fsm.adjRIBOut)
+		fsm.rib.Unregister(fsm.adjRIBOut)
 		fsm.adjRIBOut.Unregister(fsm.updateSender)
 	}
 	fsm.adjRIBIn = nil
@@ -653,23 +657,31 @@ func (fsm *FSM) openConfirmTCPFail(err error) int {
 }
 
 func (fsm *FSM) established() int {
-	fsm.adjRIBIn = rt.New(false)
-	fsm.adjRIBIn.Register(fsm.vrf)
+	fsm.adjRIBIn = adjRIBIn.New()
+	fsm.adjRIBIn.Register(fsm.rib)
 
-	fsm.adjRIBOut = rt.New(false)
+	fsm.adjRIBOut = adjRIBOut.New()
 	fsm.adjRIBOut.Register(fsm.updateSender)
 
-	fsm.vrf.Register(fsm.adjRIBOut)
+	fsm.rib.RegisterWithOptions(fsm.adjRIBOut, routingtable.ClientOptions{BestOnly: true})
 
-	go func() {
+	/*go func() {
 		for {
 			time.Sleep(time.Second * 10)
 			fmt.Printf("Dumping AdjRibIn\n")
-			routes := fsm.adjRIBIn.Dump()
+			routes := fsm.adjRIBIn.RT().Dump()
 			for _, route := range routes {
-				fmt.Printf("LPM: %s\n", route.Prefix().String())
+				fmt.Print(route.Print())
 			}
 		}
+	}()*/
+
+	go func() {
+		for {
+			fmt.Printf("ADJ-RIB-OUT: %s\n", fsm.remote.String())
+			fmt.Print(fsm.adjRIBOut.Print())
+			time.Sleep(time.Second * 11)
+		}
 	}()
 
 	for {
@@ -712,6 +724,7 @@ func (fsm *FSM) established() int {
 		case recvMsg := <-fsm.msgRecvCh:
 			msg, err := packet.Decode(bytes.NewBuffer(recvMsg.msg))
 			if err != nil {
+				fmt.Printf("Failed to decode BGP message: %v\n", recvMsg.msg)
 				switch bgperr := err.(type) {
 				case packet.BGPError:
 					sendNotification(fsm.con, bgperr.ErrorCode, bgperr.ErrorSubCode)
@@ -735,23 +748,22 @@ func (fsm *FSM) established() int {
 				u := msg.Body.(*packet.BGPUpdate)
 
 				for r := u.WithdrawnRoutes; r != nil; r = r.Next {
-					x := r.IP.([4]byte)
-					pfx := tnet.NewPfx(convert.Uint32b(x[:]), r.Pfxlen)
+					pfx := tnet.NewPfx(r.IP, r.Pfxlen)
 					fmt.Printf("LPM: Removing prefix %s\n", pfx.String())
-					fsm.adjRIBIn.RemoveRoute(pfx)
+					fsm.adjRIBIn.RemovePath(pfx, nil)
 				}
 
 				for r := u.NLRI; r != nil; r = r.Next {
-					x := r.IP.([4]byte)
-					pfx := tnet.NewPfx(convert.Uint32b(x[:]), r.Pfxlen)
+					pfx := tnet.NewPfx(r.IP, r.Pfxlen)
 					fmt.Printf("LPM: Adding prefix %s\n", pfx.String())
 
-					path := &rt.Path{
-						Type:    rt.BGPPathType,
-						BGPPath: &rt.BGPPath{},
+					path := &route.Path{
+						Type:    route.BGPPathType,
+						BGPPath: &route.BGPPath{},
 					}
 
-					for pa := u.PathAttributes; pa.Next != nil; pa = pa.Next {
+					for pa := u.PathAttributes; pa != nil; pa = pa.Next {
+						fmt.Printf("TypeCode: %d\n", pa.TypeCode)
 						switch pa.TypeCode {
 						case packet.OriginAttr:
 							path.BGPPath.Origin = pa.Value.(uint8)
@@ -760,15 +772,14 @@ func (fsm *FSM) established() int {
 						case packet.MEDAttr:
 							path.BGPPath.MED = pa.Value.(uint32)
 						case packet.NextHopAttr:
+							fmt.Printf("RECEIVED NEXT_HOP: %d\n", pa.Value.(uint32))
 							path.BGPPath.NextHop = pa.Value.(uint32)
 						case packet.ASPathAttr:
 							path.BGPPath.ASPath = pa.ASPathString()
 							path.BGPPath.ASPathLen = pa.ASPathLen()
 						}
 					}
-					// TO BE USED WITH BGP ADD PATH:
-					// fsm.adjRIBIn.AddPath(rt.NewRoute(pfx, []*rt.Path{path}))
-					fsm.adjRIBIn.ReplaceRoute(rt.NewRoute(pfx, []*rt.Path{path}))
+					fsm.adjRIBIn.AddPath(pfx, path)
 				}
 
 				continue
diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go
index 4371d5d48641a6bb672a9d0e399c96225e9a9e50..5c65732b6a3247ecf88b833c1626a2cba96b2f43 100644
--- a/protocols/bgp/server/peer.go
+++ b/protocols/bgp/server/peer.go
@@ -3,24 +3,25 @@ package server
 import (
 	"net"
 
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+
 	"github.com/bio-routing/bio-rd/config"
-	"github.com/bio-routing/bio-rd/rt"
 )
 
 type Peer struct {
 	addr     net.IP
 	asn      uint32
 	fsm      *FSM
-	vrf      *rt.RT
+	rib      *locRIB.LocRIB
 	routerID uint32
 }
 
-func NewPeer(c config.Peer, vrf *rt.RT) (*Peer, error) {
+func NewPeer(c config.Peer, rib *locRIB.LocRIB) (*Peer, error) {
 	p := &Peer{
 		addr: c.PeerAddress,
 		asn:  c.PeerAS,
-		fsm:  NewFSM(c, vrf),
-		vrf:  vrf,
+		fsm:  NewFSM(c, rib),
+		rib:  rib,
 	}
 	return p, nil
 }
diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go
index 3603c164fe60508dbc0fa75b9c33588ec650742a..8a11cd3a0641c6ff926ddc4459da157d7273db44 100644
--- a/protocols/bgp/server/server.go
+++ b/protocols/bgp/server/server.go
@@ -8,7 +8,7 @@ import (
 
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/rt"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -84,12 +84,12 @@ func (b *BGPServer) incomingConnectionWorker() {
 	}
 }
 
-func (b *BGPServer) AddPeer(c config.Peer, vrf *rt.RT) error {
+func (b *BGPServer) AddPeer(c config.Peer, rib *locRIB.LocRIB) error {
 	if c.LocalAS > uint16max || c.PeerAS > uint16max {
 		return fmt.Errorf("32bit ASNs are not supported yet")
 	}
 
-	peer, err := NewPeer(c, vrf)
+	peer, err := NewPeer(c, rib)
 	if err != nil {
 		return err
 	}
diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go
index 275b326f0188b00ba95870b0982a1cdb4b0cec41..329e97138f449f1859c5b691f9add50392880dc1 100644
--- a/protocols/bgp/server/update_sender.go
+++ b/protocols/bgp/server/update_sender.go
@@ -7,7 +7,8 @@ import (
 
 	"github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/rt"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/bio-routing/bio-rd/routingtable"
 )
 
 type UpdateSender struct {
@@ -20,50 +21,51 @@ func newUpdateSender(fsm *FSM) *UpdateSender {
 	}
 }
 
-func (u *UpdateSender) AddPath(route *rt.Route) {
-	log.Warningf("BGP Update Sender: AddPath not implemented")
+func (u *UpdateSender) AddPath(pfx net.Prefix, p *route.Path) error {
+	fmt.Printf("SENDING AN BGP UPDATE\n")
+	asPathPA, err := packet.ParseASPathStr(fmt.Sprintf("%d %s", u.fsm.localASN, p.BGPPath.ASPath))
+	if err != nil {
+		return fmt.Errorf("Unable to parse AS path: %v", err)
+	}
 
 	update := &packet.BGPUpdate{
 		PathAttributes: &packet.PathAttribute{
 			TypeCode: packet.OriginAttr,
-			Value:    uint8(packet.IGP),
+			Value:    p.BGPPath.Origin,
 			Next: &packet.PathAttribute{
 				TypeCode: packet.ASPathAttr,
-				Value: packet.ASPath{
-					{
-						Type: 2,
-						ASNs: []uint32{15169, 3329},
-					},
-				},
+				Value:    asPathPA.Value,
 				Next: &packet.PathAttribute{
 					TypeCode: packet.NextHopAttr,
-					Value:    [4]byte{100, 110, 120, 130},
+					Value:    p.BGPPath.NextHop,
 				},
 			},
 		},
 		NLRI: &packet.NLRI{
-			IP:     route.Prefix().Addr(),
-			Pfxlen: route.Pfxlen(),
+			IP:     pfx.Addr(),
+			Pfxlen: pfx.Pfxlen(),
 		},
 	}
 
 	updateBytes, err := update.SerializeUpdate()
 	if err != nil {
 		log.Errorf("Unable to serialize BGP Update: %v", err)
-		return
+		return nil
 	}
 	fmt.Printf("Sending Update: %v\n", updateBytes)
-	u.fsm.con.Write(updateBytes)
-}
-
-func (u *UpdateSender) ReplaceRoute(*rt.Route) {
-	log.Warningf("BGP Update Sender: ReplaceRoute not implemented")
+	_, err = u.fsm.con.Write(updateBytes)
+	if err != nil {
+		return fmt.Errorf("Failed sending Update: %v", err)
+	}
+	return nil
 }
 
-func (u *UpdateSender) RemovePath(*rt.Route) {
+func (u *UpdateSender) RemovePath(pfx net.Prefix, p *route.Path) bool {
 	log.Warningf("BGP Update Sender: RemovePath not implemented")
+	return false
 }
 
-func (u *UpdateSender) RemoveRoute(*net.Prefix) {
-	log.Warningf("BGP Update Sender: RemoveRoute not implemented")
+func (u *UpdateSender) UpdateNewClient(client routingtable.RouteTableClient) error {
+	log.Warningf("BGP Update Sender: RemovePath not implemented")
+	return nil
 }
diff --git a/route/bgp.go b/route/bgp.go
index 603fa3f6f81b92203f167bca72827833c85b85c9..47f7db4fc15980936e174ffa540fd3c09bb04a7e 100644
--- a/route/bgp.go
+++ b/route/bgp.go
@@ -1,5 +1,11 @@
 package route
 
+import (
+	"fmt"
+
+	"github.com/taktv6/tflow2/convert"
+)
+
 // BGPPath represents a set of BGP path attributes
 type BGPPath struct {
 	PathIdentifier uint32
@@ -14,38 +20,62 @@ type BGPPath struct {
 	Source         uint32
 }
 
-func (r *Route) bgpPathSelection() (best *Path, active []*Path) {
-	// TODO: Implement next hop lookup and compare IGP metrics
-	for _, p := range r.paths {
-		if p.Type != BGPPathType {
-			continue
-		}
+// ECMP determines if routes b and c are euqal in terms of ECMP
+func (b *BGPPath) ECMP(c *BGPPath) bool {
+	return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.MED == c.MED && b.Origin == c.Origin
+}
 
-		if len(active) == 0 {
-			active = append(active, p)
-			best = p
-			continue
-		}
+// Compare returns negative if b < c, 0 if paths are equal, positive if b > c
+func (b *BGPPath) Compare(c *BGPPath) int8 {
+	if c.LocalPref < b.LocalPref {
+		return 1
+	}
 
-		if active[0].BGPPath.ecmp(p.BGPPath) {
-			active = append(active, p)
-			if !r.bestPath.BGPPath.better(p.BGPPath) {
-				continue
-			}
+	if c.LocalPref > b.LocalPref {
+		return -1
+	}
 
-			best = p
-			continue
-		}
+	if c.ASPathLen > b.ASPathLen {
+		return 1
+	}
 
-		if !active[0].BGPPath.betterECMP(p.BGPPath) {
-			continue
-		}
+	if c.ASPathLen < b.ASPathLen {
+		return -1
+	}
 
-		active = []*Path{p}
-		best = p
+	if c.Origin > b.Origin {
+		return 1
+	}
+
+	if c.Origin < b.Origin {
+		return -1
 	}
 
-	return best, active
+	if c.MED > b.MED {
+		return 1
+	}
+
+	if c.MED < b.MED {
+		return -1
+	}
+
+	if c.BGPIdentifier < b.BGPIdentifier {
+		return 1
+	}
+
+	if c.BGPIdentifier > b.BGPIdentifier {
+		return -1
+	}
+
+	if c.Source < b.Source {
+		return 1
+	}
+
+	if c.Source > b.Source {
+		return -1
+	}
+
+	return 0
 }
 
 func (b *BGPPath) betterECMP(c *BGPPath) bool {
@@ -103,3 +133,34 @@ func (b *BGPPath) better(c *BGPPath) bool {
 func (b *BGPPath) ecmp(c *BGPPath) bool {
 	return b.LocalPref == c.LocalPref && b.ASPathLen == c.ASPathLen && b.Origin == c.Origin && b.MED == c.MED
 }
+
+func (b *BGPPath) Print() string {
+	origin := ""
+	switch b.Origin {
+	case 0:
+		origin = "Incomplete"
+	case 1:
+		origin = "EGP"
+	case 2:
+		origin = "IGP"
+	}
+	ret := fmt.Sprintf("\t\tLocal Pref: %d\n", b.LocalPref)
+	ret += fmt.Sprintf("\t\tOrigin: %s\n", origin)
+	ret += fmt.Sprintf("\t\tAS Path: %s\n", b.ASPath)
+	nh := uint32To4Byte(b.NextHop)
+	ret += fmt.Sprintf("\t\tNEXT HOP: %d.%d.%d.%d\n", nh[0], nh[1], nh[2], nh[3])
+	ret += fmt.Sprintf("\t\tMED: %d\n", b.MED)
+
+	return ret
+}
+
+func uint32To4Byte(addr uint32) [4]byte {
+	slice := convert.Uint32Byte(addr)
+	ret := [4]byte{
+		slice[0],
+		slice[1],
+		slice[2],
+		slice[3],
+	}
+	return ret
+}
diff --git a/route/path.go b/route/path.go
index 23a93889022bcd54d25e5f3d6103310647bdcdad..544b83b485c106870b8ff7a251539187c85a06d6 100644
--- a/route/path.go
+++ b/route/path.go
@@ -1,11 +1,44 @@
 package route
 
+import "fmt"
+
 type Path struct {
 	Type       uint8
 	StaticPath *StaticPath
 	BGPPath    *BGPPath
 }
 
+// Compare returns negative if p < q, 0 if paths are equal, positive if p > q
+func (p *Path) Compare(q *Path) int8 {
+	if p.Type > q.Type {
+		return 1
+	}
+
+	if p.Type < q.Type {
+		return -1
+	}
+
+	switch p.Type {
+	case BGPPathType:
+		return p.BGPPath.Compare(q.BGPPath)
+	case StaticPathType:
+		return p.StaticPath.Compare(q.StaticPath)
+	}
+
+	panic("Unknown path type")
+}
+
+func (p *Path) ECMP(q *Path) bool {
+	switch p.Type {
+	case BGPPathType:
+		return p.BGPPath.ECMP(q.BGPPath)
+	case StaticPathType:
+		return p.StaticPath.ECMP(q.StaticPath)
+	}
+
+	panic("Unknown path type")
+}
+
 func (p *Path) Equal(q *Path) bool {
 	if p == nil || q == nil {
 		return false
@@ -24,3 +57,46 @@ func (p *Path) Equal(q *Path) bool {
 
 	return true
 }
+
+// PathsDiff gets the list of elements contained by a but not b
+func PathsDiff(a, b []*Path) []*Path {
+	ret := make([]*Path, 0)
+
+	for _, pa := range a {
+		if !pathsContains(pa, b) {
+			ret = append(ret, pa)
+		}
+	}
+
+	return ret
+}
+
+func pathsContains(needle *Path, haystack []*Path) bool {
+	for _, p := range haystack {
+		if p == needle {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (p *Path) Print() string {
+	protocol := ""
+	switch p.Type {
+	case StaticPathType:
+		protocol = "static"
+	case BGPPathType:
+		protocol = "BGP"
+	}
+
+	ret := fmt.Sprintf("\tProtocol: %s\n", protocol)
+	switch p.Type {
+	case StaticPathType:
+		ret += "Not implemented yet"
+	case BGPPathType:
+		ret += p.BGPPath.Print()
+	}
+
+	return ret
+}
diff --git a/route/path_test.go b/route/path_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..b7545431b82c562e2e9e37cd921e950bf117f528
--- /dev/null
+++ b/route/path_test.go
@@ -0,0 +1,163 @@
+package route
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPathsDiff(t *testing.T) {
+	tests := []struct {
+		name     string
+		any      []*Path
+		a        []int
+		b        []int
+		expected []*Path
+	}{
+		{
+			name: "Equal",
+			any: []*Path{
+				{
+					Type: 10,
+				},
+				{
+					Type: 20,
+				},
+			},
+			a: []int{
+				0, 1,
+			},
+			b: []int{
+				0, 1,
+			},
+			expected: []*Path{},
+		},
+		{
+			name: "Left empty",
+			any: []*Path{
+				{
+					Type: 10,
+				},
+				{
+					Type: 20,
+				},
+			},
+			a: []int{},
+			b: []int{
+				0, 1,
+			},
+			expected: []*Path{},
+		},
+		{
+			name: "Right empty",
+			any: []*Path{
+				{
+					Type: 10,
+				},
+				{
+					Type: 20,
+				},
+			},
+			a: []int{0, 1},
+			b: []int{},
+			expected: []*Path{
+				{
+					Type: 10,
+				},
+				{
+					Type: 20,
+				},
+			},
+		},
+		{
+			name: "Disjunkt",
+			any: []*Path{
+				{
+					Type: 10,
+				},
+				{
+					Type: 20,
+				},
+				{
+					Type: 30,
+				},
+				{
+					Type: 40,
+				},
+			},
+			a: []int{0, 1},
+			b: []int{2, 3},
+			expected: []*Path{{
+				Type: 10,
+			},
+				{
+					Type: 20,
+				}},
+		},
+	}
+
+	for _, test := range tests {
+		listA := make([]*Path, 0)
+		for _, i := range test.a {
+			listA = append(listA, test.any[i])
+		}
+
+		listB := make([]*Path, 0)
+		for _, i := range test.b {
+			listB = append(listB, test.any[i])
+		}
+
+		res := PathsDiff(listA, listB)
+		assert.Equal(t, test.expected, res)
+	}
+}
+
+func TestPathsContains(t *testing.T) {
+	tests := []struct {
+		name     string
+		needle   int
+		haystack []*Path
+		expected bool
+	}{
+		{
+			name:   "Existent",
+			needle: 0,
+			haystack: []*Path{
+				{
+					Type: 100,
+				},
+				{
+					Type: 200,
+				},
+			},
+			expected: true,
+		},
+		{
+			name:   "Non existent",
+			needle: -1,
+			haystack: []*Path{
+				{
+					Type: 100,
+				},
+				{
+					Type: 200,
+				},
+			},
+			expected: false,
+		},
+	}
+
+	for _, test := range tests {
+		var needle *Path
+		if test.needle >= 0 {
+			needle = test.haystack[test.needle]
+		} else {
+			needle = &Path{}
+		}
+
+		res := pathsContains(needle, test.haystack)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %v", test.name, res)
+		}
+	}
+}
diff --git a/route/route.go b/route/route.go
index 90bc3972a9da22eec7e5901bb002fe0be7301b47..562f4f913411acd5d023bed79d684ef83169e83b 100644
--- a/route/route.go
+++ b/route/route.go
@@ -1,6 +1,8 @@
 package route
 
 import (
+	"fmt"
+	"sort"
 	"sync"
 
 	"github.com/bio-routing/bio-rd/net"
@@ -20,15 +22,14 @@ const ISISPathType = 4
 
 // Route links a prefix to paths
 type Route struct {
-	pfx         net.Prefix
-	mu          sync.Mutex
-	bestPath    *Path
-	activePaths []*Path
-	paths       []*Path
+	pfx       net.Prefix
+	mu        sync.Mutex
+	paths     []*Path
+	ecmpPaths uint
 }
 
-// NewRoute generates a new route
-func NewRoute(pfx net.Prefix, p *Path) *Route {
+// NewRoute generates a new route with paths p
+func NewRoute(pfx net.Prefix, p ...*Path) *Route {
 	r := &Route{
 		pfx: pfx,
 	}
@@ -38,10 +39,21 @@ func NewRoute(pfx net.Prefix, p *Path) *Route {
 		return r
 	}
 
-	r.paths = []*Path{p}
+	r.paths = append(r.paths, p...)
 	return r
 }
 
+// Copy returns a copy of route r
+func (r *Route) Copy() *Route {
+	new := &Route{
+		pfx:       r.pfx,
+		ecmpPaths: r.ecmpPaths,
+	}
+	new.paths = make([]*Path, len(r.paths))
+	copy(new.paths, r.paths)
+	return new
+}
+
 // Prefix gets the prefix of route `r`
 func (r *Route) Prefix() net.Prefix {
 	return r.pfx
@@ -60,7 +72,7 @@ func (r *Route) Pfxlen() uint8 {
 // Paths returns a copy of the list of paths associated with route r
 func (r *Route) Paths() []*Path {
 	if r.paths == nil {
-		return nil
+		return []*Path{}
 	}
 
 	ret := make([]*Path, len(r.paths))
@@ -68,6 +80,34 @@ func (r *Route) Paths() []*Path {
 	return ret
 }
 
+// ECMPPathCount returns the count of ecmp paths for route r
+func (r *Route) ECMPPathCount() uint {
+	return r.ecmpPaths
+}
+
+// ECMPPaths returns a copy of the list of paths associated with route r
+func (r *Route) ECMPPaths() []*Path {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+
+	if len(r.paths) == 0 {
+		return nil
+	}
+
+	ret := make([]*Path, r.ecmpPaths)
+	copy(ret, r.paths[0:r.ecmpPaths])
+	return ret
+}
+
+// BestPath returns the current best path. nil if non exists
+func (r *Route) BestPath() *Path {
+	if len(r.paths) == 0 {
+		return nil
+	}
+
+	return r.paths[0]
+}
+
 // AddPath adds path p to route r
 func (r *Route) AddPath(p *Path) {
 	if p == nil {
@@ -109,3 +149,60 @@ func removePath(paths []*Path, remove *Path) []*Path {
 	copy(paths[i:], paths[i+1:])
 	return paths[:len(paths)-1]
 }
+
+// PathSelection recalculates the best path + active paths
+func (r *Route) PathSelection() {
+	r.mu.Lock()
+	defer r.mu.Unlock()
+
+	sort.Slice(r.paths, func(i, j int) bool {
+		return r.paths[i].Compare(r.paths[j]) == -1
+	})
+
+	r.updateEqualPathCount()
+}
+
+func (r *Route) updateEqualPathCount() {
+	count := uint(1)
+	for i := 0; i < len(r.paths)-1; i++ {
+		if !r.paths[i].ECMP(r.paths[i+1]) {
+			break
+		}
+		count++
+	}
+
+	r.ecmpPaths = count
+}
+
+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
+}
+
+// Print returns a prinatble representation of route `r`
+func (r *Route) Print() string {
+	ret := fmt.Sprintf("%s:\n", r.pfx.String())
+	//ret += fmt.Sprintf("Best path:\n")
+	//ret += r.bestPath.Print()
+	/*ret += fmt.Sprintf("Active Paths:\n")
+	for _, p := range r.activePaths {
+		ret += p.Print()
+	}*/
+	ret += fmt.Sprintf("All Paths:\n")
+	for _, p := range r.paths {
+		ret += p.Print()
+	}
+
+	return ret
+}
diff --git a/route/route_test.go b/route/route_test.go
index 598a38d76f0bd63052f1aee5add7c2df45784498..86ff434675c2922f2f5c73803e4801c400751b60 100644
--- a/route/route_test.go
+++ b/route/route_test.go
@@ -262,6 +262,41 @@ func TestRouteRemovePath(t *testing.T) {
 	}
 }
 
+func TestCopy(t *testing.T) {
+	tests := []struct {
+		name     string
+		route    *Route
+		expected *Route
+	}{
+		{
+			name: "",
+			route: &Route{
+				pfx:       net.NewPfx(1000, 8),
+				ecmpPaths: 2,
+				paths: []*Path{
+					{
+						Type: 100,
+					},
+				},
+			},
+			expected: &Route{
+				pfx:       net.NewPfx(1000, 8),
+				ecmpPaths: 2,
+				paths: []*Path{
+					{
+						Type: 100,
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res := test.route.Copy()
+		assert.Equal(t, test.expected, res)
+	}
+}
+
 func strAddr(s string) uint32 {
 	ret, _ := net.StrToAddr(s)
 	return ret
diff --git a/route/static.go b/route/static.go
index 1ae8b302eef37709b167cbe07c75df663a7d055b..483138f04874ff7f50185ba3fcfb04fb007c6029 100644
--- a/route/static.go
+++ b/route/static.go
@@ -5,23 +5,21 @@ type StaticPath struct {
 	NextHop uint32
 }
 
-func (r *Route) staticPathSelection() (best *Path, active []*Path) {
-	if r.paths == nil {
-		return nil, nil
-	}
-
+func (r *Route) staticPathSelection() {
 	if len(r.paths) == 0 {
-		return nil, nil
+		return
 	}
 
-	for _, p := range r.paths {
-		if p.Type != StaticPathType {
-			continue
-		}
+	r.ecmpPaths = uint(len(r.paths))
+	return
+}
 
-		active = append(active, p)
-		best = p
-	}
+// Compare returns negative if s < t, 0 if paths are equal, positive if s > t
+func (s *StaticPath) Compare(t *StaticPath) int8 {
+	return 0
+}
 
-	return
+// ECMP determines if path s and t are equal in terms of ECMP
+func (s *StaticPath) ECMP(t *StaticPath) bool {
+	return true
 }
diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go
index 33366d2192887e334549118c53c085846cf3db31..1427278bbd5aa6c465c16bf2ac4e1462fd5a34d8 100644
--- a/routingtable/adjRIBIn/adj_rib_in.go
+++ b/routingtable/adjRIBIn/adj_rib_in.go
@@ -10,13 +10,13 @@ import (
 
 // AdjRIBIn represents an Adjacency RIB In as described in RFC4271
 type AdjRIBIn struct {
-	rt *routingtable.RoutingTable
 	routingtable.ClientManager
+	rt *routingtable.RoutingTable
 	mu sync.RWMutex
 }
 
-// NewAdjRIBIn creates a new Adjacency RIB In
-func NewAdjRIBIn() *AdjRIBIn {
+// New creates a new Adjacency RIB In
+func New() *AdjRIBIn {
 	a := &AdjRIBIn{
 		rt: routingtable.NewRoutingTable(),
 	}
@@ -79,3 +79,7 @@ func (a *AdjRIBIn) removePathsFromClients(pfx net.Prefix, paths []*route.Path) {
 		}
 	}
 }
+
+func (a *AdjRIBIn) RT() *routingtable.RoutingTable {
+	return a.rt
+}
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
new file mode 100644
index 0000000000000000000000000000000000000000..580b86b8aa522f00b24e9af27825e6e7514bc00f
--- /dev/null
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -0,0 +1,85 @@
+package adjRIBOut
+
+import (
+	"fmt"
+	"sync"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/bio-routing/bio-rd/routingtable"
+)
+
+// AdjRIBOut represents an Adjacency RIB In as described in RFC4271
+type AdjRIBOut struct {
+	rt *routingtable.RoutingTable
+	routingtable.ClientManager
+	mu sync.RWMutex
+}
+
+// New creates a new Adjacency RIB In
+func New() *AdjRIBOut {
+	a := &AdjRIBOut{
+		rt: routingtable.NewRoutingTable(),
+	}
+	a.ClientManager = routingtable.NewClientManager(a)
+	return a
+}
+
+// UpdateNewClient sends current state to a new client
+func (a *AdjRIBOut) UpdateNewClient(client routingtable.RouteTableClient) error {
+	return fmt.Errorf("Not supported")
+}
+
+// AddPath replaces the path for prefix `pfx`. If the prefix doesn't exist it is added.
+func (a *AdjRIBOut) AddPath(pfx net.Prefix, p *route.Path) error {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+
+	oldPaths := a.rt.ReplacePath(pfx, p)
+	a.removePathsFromClients(pfx, oldPaths)
+
+	for _, client := range a.ClientManager.Clients() {
+		client.AddPath(pfx, p)
+	}
+	return nil
+}
+
+// RemovePath removes the path for prefix `pfx`
+func (a *AdjRIBOut) RemovePath(pfx net.Prefix, p *route.Path) bool {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+
+	r := a.rt.Get(pfx)
+	if r == nil {
+		return false
+	}
+
+	oldPaths := r.Paths()
+	for _, path := range oldPaths {
+		a.rt.RemovePath(pfx, path)
+	}
+
+	a.removePathsFromClients(pfx, oldPaths)
+	return true
+}
+
+func (a *AdjRIBOut) removePathsFromClients(pfx net.Prefix, paths []*route.Path) {
+	for _, path := range paths {
+		for _, client := range a.ClientManager.Clients() {
+			client.RemovePath(pfx, path)
+		}
+	}
+}
+
+func (a *AdjRIBOut) Print() string {
+	a.mu.RLock()
+	defer a.mu.RUnlock()
+
+	ret := fmt.Sprintf("DUMPING ADJ-RIB-OUT:\n")
+	routes := a.rt.Dump()
+	for _, r := range routes {
+		ret += fmt.Sprintf("%s\n", r.Prefix().String())
+	}
+
+	return ret
+}
diff --git a/routingtable/client_manager.go b/routingtable/client_manager.go
index bb86111d6f89cd8d98d15396e211050dfe8872ba..ee0275c3f2358ae96b4e297b17b540e29139bf90 100644
--- a/routingtable/client_manager.go
+++ b/routingtable/client_manager.go
@@ -1,25 +1,63 @@
 package routingtable
 
+import (
+	"sync"
+)
+
+// ClientOptions represents options for a client
+type ClientOptions struct {
+	BestOnly bool
+	EcmpOnly bool
+	MaxPaths uint
+}
+
+// GetMaxPaths calculates the maximum amount of wanted paths given that ecmpPaths paths exist
+func (c *ClientOptions) GetMaxPaths(ecmpPaths uint) uint {
+	if c.BestOnly {
+		return 1
+	}
+
+	if c.EcmpOnly {
+		return ecmpPaths
+	}
+
+	return c.MaxPaths
+}
+
 // ClientManager manages clients of routing tables (observer pattern)
 type ClientManager struct {
-	clients map[RouteTableClient]struct{} // Ensures a client registers at most once
+	clients map[RouteTableClient]ClientOptions
 	master  RouteTableClient
+	mu      sync.RWMutex
 }
 
 // NewClientManager creates and initializes a new client manager
 func NewClientManager(master RouteTableClient) ClientManager {
 	return ClientManager{
-		clients: make(map[RouteTableClient]struct{}, 0),
+		clients: make(map[RouteTableClient]ClientOptions, 0),
 		master:  master,
 	}
 }
 
+// GetOptions gets the options for a registred client
+func (c *ClientManager) GetOptions(client RouteTableClient) ClientOptions {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+
+	return c.clients[client]
+}
+
 // Register registers a client for updates
 func (c *ClientManager) Register(client RouteTableClient) {
-	if c.clients == nil {
-		c.clients = make(map[RouteTableClient]struct{}, 0)
-	}
-	c.clients[client] = struct{}{}
+	c.RegisterWithOptions(client, ClientOptions{BestOnly: true})
+}
+
+// RegisterWithOptions registers a client with options for updates
+func (c *ClientManager) RegisterWithOptions(client RouteTableClient, opt ClientOptions) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	c.clients[client] = opt
 	c.master.UpdateNewClient(client)
 }
 
diff --git a/routingtable/client_manager_test.go b/routingtable/client_manager_test.go
index d05370ce55e0a3d4608e131b0b371b6ef5e6f4fc..674a9a4ebd8ed8b0a691db6613eb4a931a606838 100644
--- a/routingtable/client_manager_test.go
+++ b/routingtable/client_manager_test.go
@@ -64,3 +64,42 @@ func TestClients(t *testing.T) {
 		assert.Equal(t, test.expected, ret)
 	}
 }
+
+func TestGetMaxPaths(t *testing.T) {
+	tests := []struct {
+		name          string
+		clientOptions ClientOptions
+		ecmpPaths     uint
+		expected      uint
+	}{
+		{
+			name: "Test #1",
+			clientOptions: ClientOptions{
+				BestOnly: true,
+			},
+			ecmpPaths: 8,
+			expected:  1,
+		},
+		{
+			name: "Test #2",
+			clientOptions: ClientOptions{
+				EcmpOnly: true,
+			},
+			ecmpPaths: 8,
+			expected:  8,
+		},
+		{
+			name: "Test #3",
+			clientOptions: ClientOptions{
+				MaxPaths: 100,
+			},
+			ecmpPaths: 10,
+			expected:  100,
+		},
+	}
+
+	for _, test := range tests {
+		res := test.clientOptions.GetMaxPaths(test.ecmpPaths)
+		assert.Equal(t, test.expected, res)
+	}
+}
diff --git a/routingtable/locRIB/loc_rib.go b/routingtable/locRIB/loc_rib.go
new file mode 100644
index 0000000000000000000000000000000000000000..73a6a2ff7251e0644fd80471111694bd83bf02cd
--- /dev/null
+++ b/routingtable/locRIB/loc_rib.go
@@ -0,0 +1,146 @@
+package locRIB
+
+import (
+	"fmt"
+	"math"
+	"sync"
+
+	"github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/bio-routing/bio-rd/routingtable"
+)
+
+// LocRIB represents a routing information base
+type LocRIB struct {
+	routingtable.ClientManager
+	rt *routingtable.RoutingTable
+	mu sync.RWMutex
+}
+
+// New creates a new routing information base
+func New() *LocRIB {
+	a := &LocRIB{
+		rt: routingtable.NewRoutingTable(),
+	}
+	a.ClientManager = routingtable.NewClientManager(a)
+	return a
+}
+
+// UpdateNewClient sends current state to a new client
+func (a *LocRIB) UpdateNewClient(client routingtable.RouteTableClient) error {
+	a.mu.RLock()
+	defer a.mu.RUnlock()
+
+	routes := a.rt.Dump()
+	for _, r := range routes {
+		a.propagateChanges(&route.Route{}, r)
+	}
+
+	return nil
+}
+
+// AddPath replaces the path for prefix `pfx`. If the prefix doesn't exist it is added.
+func (a *LocRIB) AddPath(pfx net.Prefix, p *route.Path) error {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+
+	routeExisted := false
+	oldRoute := &route.Route{}
+	r := a.rt.Get(pfx)
+	if r != nil {
+		oldRoute = r.Copy()
+		routeExisted = true
+	}
+
+	a.rt.AddPath(pfx, p)
+	if !routeExisted {
+		r = a.rt.Get(pfx)
+	}
+
+	r.PathSelection()
+
+	newRoute := r.Copy()
+
+	fmt.Printf("NEW: %v\n", newRoute.Paths())
+	fmt.Printf("OLD: %v\n", oldRoute.Paths())
+
+	a.propagateChanges(oldRoute, newRoute)
+	return nil
+}
+
+// RemovePath removes the path for prefix `pfx`
+func (a *LocRIB) RemovePath(pfx net.Prefix, p *route.Path) bool {
+	a.mu.Lock()
+	defer a.mu.Unlock()
+
+	var oldRoute *route.Route
+	r := a.rt.Get(pfx)
+	if r != nil {
+		oldRoute = r.Copy()
+	}
+
+	a.rt.RemovePath(pfx, p)
+	r.PathSelection()
+
+	r = a.rt.Get(pfx)
+	newRoute := r.Copy()
+
+	fmt.Printf("NEW: %v\n", newRoute.Paths())
+	fmt.Printf("OLD: %v\n", oldRoute.Paths())
+
+	a.propagateChanges(oldRoute, newRoute)
+	return true
+}
+
+func (a *LocRIB) propagateChanges(oldRoute *route.Route, newRoute *route.Route) {
+	a.removePathsFromClients(oldRoute, newRoute)
+	a.addPathsToClients(oldRoute, newRoute)
+}
+
+func (a *LocRIB) addPathsToClients(oldRoute *route.Route, newRoute *route.Route) {
+	for _, client := range a.ClientManager.Clients() {
+		opts := a.ClientManager.GetOptions(client)
+		oldMaxPaths := opts.GetMaxPaths(oldRoute.ECMPPathCount())
+		newMaxPaths := opts.GetMaxPaths(newRoute.ECMPPathCount())
+
+		oldPathsLimit := int(math.Min(float64(oldMaxPaths), float64(len(oldRoute.Paths()))))
+		newPathsLimit := int(math.Min(float64(newMaxPaths), float64(len(newRoute.Paths()))))
+
+		advertise := route.PathsDiff(newRoute.Paths()[0:newPathsLimit], oldRoute.Paths()[0:oldPathsLimit])
+		fmt.Printf("ADVERTISING PATHS %v TO CLIENTS\n", advertise)
+
+		for _, p := range advertise {
+			client.AddPath(newRoute.Prefix(), p)
+		}
+	}
+}
+
+func (a *LocRIB) removePathsFromClients(oldRoute *route.Route, newRoute *route.Route) {
+	for _, client := range a.ClientManager.Clients() {
+		opts := a.ClientManager.GetOptions(client)
+		oldMaxPaths := opts.GetMaxPaths(oldRoute.ECMPPathCount())
+		newMaxPaths := opts.GetMaxPaths(newRoute.ECMPPathCount())
+
+		oldPathsLimit := int(math.Min(float64(oldMaxPaths), float64(len(oldRoute.Paths()))))
+		newPathsLimit := int(math.Min(float64(newMaxPaths), float64(len(newRoute.Paths()))))
+
+		withdraw := route.PathsDiff(oldRoute.Paths()[0:oldPathsLimit], newRoute.Paths()[0:newPathsLimit])
+
+		for _, p := range withdraw {
+			client.RemovePath(newRoute.Prefix(), p)
+		}
+	}
+}
+
+func (a *LocRIB) Print() string {
+	a.mu.RLock()
+	defer a.mu.RUnlock()
+
+	ret := "Loc-RIB DUMP:\n"
+	routes := a.rt.Dump()
+	for _, r := range routes {
+		ret += fmt.Sprintf("%s\n", r.Prefix().String())
+	}
+
+	return ret
+}
diff --git a/rt/bgp.go b/rt/bgp.go
deleted file mode 100644
index 9fd3e56c0d92d8459a9375eb4020c8ef35ddc173..0000000000000000000000000000000000000000
--- a/rt/bgp.go
+++ /dev/null
@@ -1,160 +0,0 @@
-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
-	BGPIdentifier  uint32
-	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() (best *Path, active []*Path) {
-	// TODO: Implement next hop lookup and compare IGP metrics
-	for _, p := range r.paths {
-		if p.Type != BGPPathType {
-			continue
-		}
-
-		if len(active) == 0 {
-			active = append(active, p)
-			continue
-		}
-
-		if active[0].BGPPath.ecmp(p.BGPPath) {
-			active = append(active, p)
-			if !r.bestPath.BGPPath.better(p.BGPPath) {
-				continue
-			}
-
-			best = p
-			continue
-		}
-
-		if !active[0].BGPPath.betterECMP(p.BGPPath) {
-			continue
-		}
-
-		active = []*Path{p}
-	}
-
-	return best, active
-}
-
-func (b *BGPPath) betterECMP(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) better(c *BGPPath) bool {
-	if b.betterECMP(c) {
-		return true
-	}
-
-	if c.BGPIdentifier < b.BGPIdentifier {
-		return true
-	}
-
-	if c.Source < b.Source {
-		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/client_manager.go b/rt/client_manager.go
deleted file mode 100644
index 723b6e94da5e300f0dddd0d31e1ed487d77f1506..0000000000000000000000000000000000000000
--- a/rt/client_manager.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package rt
-
-type ClientManager struct {
-	clients      map[RouteTableClient]struct{} // Ensures a client registers at most once
-	routingTable *RT
-}
-
-func (c *ClientManager) Register(client RouteTableClient) {
-	if c.clients == nil {
-		c.clients = make(map[RouteTableClient]struct{}, 0)
-	}
-	c.clients[client] = struct{}{}
-	c.routingTable.updateNewClient(client)
-}
-
-func (c *ClientManager) Unregister(client RouteTableClient) {
-	if _, ok := c.clients[client]; !ok {
-		return
-	}
-	delete(c.clients, client)
-}
diff --git a/rt/filter.go b/rt/filter.go
deleted file mode 100644
index f68a6d421451f850c3e65a7a2816a909608e5bf1..0000000000000000000000000000000000000000
--- a/rt/filter.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package rt
-
-type Filter struct {
-	ClientManager
-}
-
-func NewFilter() *Filter {
-	return &Filter{}
-}
-
-func (f *Filter) Add(r *Route) {
-	for client := range f.clients {
-		client.AddPath(r)
-	}
-}
-
-func (f *Filter) Remove(r *Route) {
-	for client := range f.clients {
-		client.RemovePath(r)
-	}
-}
diff --git a/rt/lpm_test.go.dis b/rt/lpm_test.go.dis
deleted file mode 100644
index 90f9e450ba42b376a81b239f90285aca497902e7..0000000000000000000000000000000000000000
--- a/rt/lpm_test.go.dis
+++ /dev/null
@@ -1,673 +0,0 @@
-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
deleted file mode 100644
index d271c914a99920a77515c64ddb04ac96a84893f4..0000000000000000000000000000000000000000
--- a/rt/route.go
+++ /dev/null
@@ -1,152 +0,0 @@
-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
-	bestPath    *Path
-	activePaths []*Path
-	paths       []*Path
-}
-
-func NewRoute(pfx *net.Prefix, paths []*Path) *Route {
-	r := &Route{
-		pfx:   pfx,
-		paths: paths,
-	}
-
-	return r
-}
-
-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
-}
-
-// returns a list of Paths that are in a but not in b
-func missingPaths(a, b []*Path) []*Path {
-	ret := make([]*Path, 0)
-	for _, p := range a {
-		found := false
-		for _, q := range b {
-			if *p == *q {
-				found = true
-				break
-			}
-		}
-		if !found {
-			ret = append(ret, p)
-		}
-	}
-
-	return ret
-}
-
-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 (r *Route) removeAllPaths() {
-	r.paths = make([]*Path, 0)
-}
-
-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
-	var active []*Path
-	protocol := getBestProtocol(r.paths)
-
-	switch protocol {
-	case StaticPathType:
-		best, active = r.staticPathSelection()
-	case BGPPathType:
-		best, active = r.bgpPathSelection()
-	}
-
-	r.bestPath = best
-	r.activePaths = active
-}
-
-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
deleted file mode 100644
index 7b381809d414d7c65f043dd403e6c5b5f6423825..0000000000000000000000000000000000000000
--- a/rt/route_test.go
+++ /dev/null
@@ -1,473 +0,0 @@
-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),
-				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)
-	}
-}
-
-func TestGetBestProtocol(t *testing.T) {
-	tests := []struct {
-		name     string
-		input    []*Path
-		expected uint8
-	}{
-		{
-			name: "Foo",
-			input: []*Path{
-				{
-					Type: BGPPathType,
-				},
-				{
-					Type: StaticPathType,
-				},
-			},
-			expected: StaticPathType,
-		},
-	}
-
-	for _, test := range tests {
-		res := getBestProtocol(test.input)
-		assert.Equal(t, test.expected, res)
-	}
-}
-
-func TestMissingPaths(t *testing.T) {
-	tests := []struct {
-		name     string
-		a        []*Path
-		b        []*Path
-		expected []*Path
-	}{
-		{
-			name: "None missing #2",
-			a: []*Path{
-				{
-					Type: 1,
-				},
-				{
-					Type: 2,
-				},
-			},
-			b: []*Path{
-				{
-					Type: 1,
-				},
-				{
-					Type: 2,
-				},
-				{
-					Type: 3,
-				},
-			},
-			expected: []*Path{},
-		},
-		{
-			name: "None missing",
-			a: []*Path{
-				{
-					Type: 1,
-				},
-				{
-					Type: 2,
-				},
-			},
-			b: []*Path{
-				{
-					Type: 1,
-				},
-				{
-					Type: 2,
-				},
-			},
-			expected: []*Path{},
-		},
-		{
-			name: "One missing",
-			a: []*Path{
-				{
-					Type: 1,
-				},
-				{
-					Type: 2,
-				},
-			},
-			b: []*Path{
-				{
-					Type: 1,
-				},
-			},
-			expected: []*Path{
-				{
-					Type: 2,
-				},
-			},
-		},
-	}
-
-	for _, test := range tests {
-		res := missingPaths(test.a, test.b)
-		assert.Equal(t, test.expected, res)
-	}
-}
diff --git a/rt/routing_table.go b/rt/routing_table.go
deleted file mode 100644
index 9e03e03d8aaf9617983d138aabaf88235f4222aa..0000000000000000000000000000000000000000
--- a/rt/routing_table.go
+++ /dev/null
@@ -1,470 +0,0 @@
-package rt
-
-import (
-	"fmt"
-	"sync"
-
-	"github.com/bio-routing/bio-rd/net"
-)
-
-type RouteTableClient interface {
-	AddPath(*Route)
-	ReplaceRoute(*Route)
-	RemovePath(*Route)
-	RemoveRoute(*net.Prefix)
-}
-
-// RT represents a routing table
-type RT struct {
-	root            *node
-	selectBestPaths bool
-	mu              sync.RWMutex
-	ClientManager
-}
-
-// node is a node in the compressed trie that is used to implement a routing table
-type node struct {
-	skip  uint8
-	dummy bool
-	route *Route
-	l     *node
-	h     *node
-}
-
-// New creates a new empty LPM
-func New(selectBestPaths bool) *RT {
-	rt := &RT{
-		selectBestPaths: selectBestPaths,
-	}
-
-	rt.ClientManager.routingTable = rt
-	return rt
-}
-
-func (rt *RT) updateNewClient(client RouteTableClient) {
-	rt.root.updateNewClient(client)
-}
-
-func (n *node) updateNewClient(client RouteTableClient) {
-	if n == nil {
-		return
-	}
-
-	if !n.dummy {
-		client.AddPath(n.route)
-	}
-
-	n.l.updateNewClient(client)
-	n.h.updateNewClient(client)
-}
-
-func (rt *RT) updatePathSelection(route *Route) {
-	fmt.Printf("updatePathSelection\n")
-	formerActivePaths := rt.Get(route.pfx, false)[0].activePaths
-	activePaths := rt.selectBestPath(route).route.activePaths
-
-	fmt.Printf("formerActivePaths: %v\n", formerActivePaths)
-	fmt.Printf("activePaths: %v\n", activePaths)
-	x := missingPaths(activePaths, formerActivePaths)
-	fmt.Printf("x: %v\n", x)
-
-	for _, advertisePath := range x {
-		adervtiseRoute := &Route{
-			pfx:   route.pfx,
-			paths: []*Path{advertisePath},
-		}
-		for client := range rt.clients {
-			fmt.Printf("Propagating an Update via AddPath()")
-			client.AddPath(adervtiseRoute)
-		}
-	}
-
-	for _, withdrawPath := range missingPaths(formerActivePaths, activePaths) {
-		withdrawRoute := &Route{
-			pfx:   route.pfx,
-			paths: []*Path{withdrawPath},
-		}
-		for client := range rt.clients {
-			fmt.Printf("Propagating an Update via RemovePath()")
-			client.RemovePath(withdrawRoute)
-		}
-	}
-}
-
-func (rt *RT) AddPath(route *Route) {
-	rt.addPath(route)
-	if rt.selectBestPaths {
-		rt.updatePathSelection(route)
-		return
-	}
-
-	for client := range rt.clients {
-		client.AddPath(route)
-	}
-}
-
-// RemovePath removes a path from the trie
-func (rt *RT) RemovePath(route *Route) {
-	rt.root.removePath(route)
-
-	for client := range rt.clients {
-		client.RemovePath(route)
-	}
-}
-
-// RemoveRoute removes a prefix from the rt including all it's paths
-func (rt *RT) RemoveRoute(pfx *net.Prefix) {
-	if rt.selectBestPaths {
-		return
-	}
-
-	r := rt.Get(pfx, false)
-	if len(r) == 0 {
-		return
-	}
-
-	for client := range rt.clients {
-		for _, path := range r[0].paths {
-			withdrawRoute := NewRoute(pfx, []*Path{path})
-			client.RemovePath(withdrawRoute)
-		}
-	}
-
-	rt.root.removeRoute(pfx)
-}
-
-// ReplaceRoute replaces all paths of a route. Route is added if it doesn't exist yet.
-func (rt *RT) ReplaceRoute(route *Route) {
-	fmt.Printf("Replacing a route!\n")
-	if rt.selectBestPaths {
-		fmt.Printf("Ignoring because rt.selectBestPaths is false\n")
-		return
-	}
-
-	r := rt.Get(route.pfx, false)
-	if len(r) > 0 {
-		rt.RemoveRoute(route.pfx)
-	}
-	rt.addPath(route)
-	rt.updatePathSelection(route)
-}
-
-// LPM performs a longest prefix match for pfx on lpm
-func (rt *RT) LPM(pfx *net.Prefix) (res []*Route) {
-	if rt.root == nil {
-		return nil
-	}
-
-	rt.root.lpm(pfx, &res)
-	return res
-}
-
-// Get get's prefix pfx from the LPM
-func (rt *RT) Get(pfx *net.Prefix, moreSpecifics bool) (res []*Route) {
-	if rt.root == nil {
-		return nil
-	}
-
-	node := rt.root.get(pfx)
-	if moreSpecifics {
-		return node.dumpPfxs(res)
-	}
-
-	if node == nil {
-		return nil
-	}
-
-	return []*Route{
-		node.route,
-	}
-}
-
-func (rt *RT) addPath(route *Route) {
-	if rt.root == nil {
-		rt.root = newNode(route, route.Pfxlen(), false)
-		return
-	}
-
-	rt.root = rt.root.insert(route)
-}
-
-func (rt *RT) selectBestPath(route *Route) *node {
-	if rt.root == nil {
-		return nil
-	}
-
-	node := rt.root.get(route.pfx)
-	if !rt.selectBestPaths {
-		// If we don't select best path(s) evey path is best path
-		node.route.activePaths = make([]*Path, len(node.route.paths))
-		copy(node.route.activePaths, node.route.paths)
-		return node
-	}
-
-	node.route.bestPaths()
-	return node
-}
-
-func newNode(route *Route, skip uint8, dummy bool) *node {
-	n := &node{
-		route: route,
-		skip:  skip,
-		dummy: dummy,
-	}
-	return n
-}
-
-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) replaceRoute(route *Route) {
-	if n == nil {
-		return
-	}
-
-	if *n.route.Prefix() == *route.Prefix() {
-		n.route = route
-		n.dummy = false
-		return
-	}
-
-	b := getBitUint32(route.Prefix().Addr(), n.route.Pfxlen()+1)
-	if !b {
-		n.l.replaceRoute(route)
-		return
-	}
-	n.h.replaceRoute(route)
-	return
-}
-
-func (n *node) removeRoute(pfx *net.Prefix) {
-	if n == nil {
-		return
-	}
-
-	if *n.route.Prefix() == *pfx {
-		if n.dummy {
-			return
-		}
-
-		// TODO: Remove node if possible
-		n.dummy = true
-		return
-	}
-
-	b := getBitUint32(pfx.Addr(), n.route.Pfxlen()+1)
-	if !b {
-		n.l.removeRoute(pfx)
-		return
-	}
-	n.h.removeRoute(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()) {
-		route.bestPaths()
-		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 {
-		route.bestPaths()
-		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 {
-		route.bestPaths()
-		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
-}
-
-// Dump dumps all routes in table rt into a slice
-func (rt *RT) Dump() []*Route {
-	res := make([]*Route, 0)
-	return rt.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
deleted file mode 100644
index 093af87b8184fa90cc3fc20c926675574433c5b0..0000000000000000000000000000000000000000
--- a/rt/routing_table_test.go
+++ /dev/null
@@ -1,605 +0,0 @@
-package rt
-
-import (
-	"testing"
-
-	net "github.com/bio-routing/bio-rd/net"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestNew(t *testing.T) {
-	l := New(false)
-	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(strAddr("10.0.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("10.128.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-			remove: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-			expected: []*Route{
-				{
-					pfx: net.NewPfx(strAddr("10.0.0.0"), 9),
-					paths: []*Path{
-						{
-							Type:    BGPPathType,
-							BGPPath: &BGPPath{},
-						},
-					},
-				},
-				{
-					pfx: net.NewPfx(strAddr("10.128.0.0"), 9),
-					paths: []*Path{
-						{
-							Type:    BGPPathType,
-							BGPPath: &BGPPath{},
-						},
-					},
-				},
-			},
-		},
-		/*{
-			name: "Remove a path that is one of two for a prefix",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type: BGPPathType,
-						BGPPath: &BGPPath{
-							LocalPref: 1000,
-						},
-					},
-					{
-						Type: BGPPathType,
-						BGPPath: &BGPPath{
-							LocalPref: 2000,
-						},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("10.128.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-			remove: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type: BGPPathType,
-						BGPPath: &BGPPath{
-							LocalPref: 1000,
-						},
-					},
-				}),
-			},
-			expected: []*Route{
-				{
-					pfx: net.NewPfx(strAddr("10.0.0.0"), 8),
-					paths: []*Path{
-						{
-							Type: BGPPathType,
-							BGPPath: &BGPPath{
-								LocalPref: 2000,
-							},
-						},
-					},
-					activePaths: []*Path{
-						{
-							Type: BGPPathType,
-							BGPPath: &BGPPath{
-								LocalPref: 2000,
-							},
-						},
-					},
-				},
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("10.128.0.0"), 9), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-		},*/
-	}
-
-	for _, test := range tests {
-		rt := New(false)
-		for _, route := range test.routes {
-			rt.AddPath(route)
-		}
-
-		for _, route := range test.remove {
-			rt.RemovePath(route)
-		}
-
-		res := rt.Dump()
-		assert.Equal(t, test.expected, res)
-	}
-}
-
-func TestRemovePfx(t *testing.T) {
-	tests := []struct {
-		name     string
-		routes   []*Route
-		remove   []*net.Prefix
-		expected []*Route
-	}{
-		{
-			name: "Remove non-existent prefix",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("100.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-			remove: []*net.Prefix{
-				net.NewPfx(0, 0),
-			},
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-				NewRoute(net.NewPfx(strAddr("100.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-		},
-		{
-			name: "Remove final prefix",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), []*Path{
-					{
-						Type:    BGPPathType,
-						BGPPath: &BGPPath{},
-					},
-				}),
-			},
-			remove: []*net.Prefix{
-				net.NewPfx(strAddr("10.0.0.0"), 8),
-			},
-			expected: []*Route{},
-		},
-	}
-
-	for _, test := range tests {
-		lpm := New(false)
-		for _, route := range test.routes {
-			lpm.AddPath(route)
-		}
-
-		for _, pfx := range test.remove {
-			lpm.RemoveRoute(pfx)
-		}
-
-		res := lpm.Dump()
-		assert.Equal(t, test.expected, res)
-	}
-}
-
-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 TestLPM(t *testing.T) {
-	tests := []struct {
-		name     string
-		routes   []*Route
-		needle   *net.Prefix
-		expected []*Route
-	}{
-		{
-			name:     "LPM for non-existent route",
-			routes:   []*Route{},
-			needle:   net.NewPfx(strAddr("10.0.0.0"), 32),
-			expected: nil,
-		},
-		{
-			name: "Positive LPM test",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-			needle: net.NewPfx(167772160, 32), // 10.0.0.0/32
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-			},
-		},
-		/*{
-			name: "Exact match",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-			needle: net.NewPfx(strAddr("10.0.0.0"), 10),
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-		},*/
-	}
-
-	for _, test := range tests {
-		rt := New(false)
-		for _, route := range test.routes {
-			rt.AddPath(route)
-		}
-		assert.Equal(t, test.expected, rt.LPM(test.needle))
-	}
-}
-
-func TestGet(t *testing.T) {
-	tests := []struct {
-		name          string
-		moreSpecifics bool
-		routes        []*Route
-		needle        *net.Prefix
-		expected      []*Route
-	}{
-		{
-			name:          "Test 1: Search pfx and dump route + more specifics",
-			moreSpecifics: true,
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-			needle: net.NewPfx(strAddr("10.0.0.0"), 8),
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-			},
-		},
-		{
-			name: "Test 2: Search pfx and don't dump more specifics",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-			needle: net.NewPfx(strAddr("10.0.0.0"), 8),
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-			},
-		},
-		{
-			name:     "Test 3: Empty table",
-			routes:   []*Route{},
-			needle:   net.NewPfx(strAddr("10.0.0.0"), 32),
-			expected: nil,
-		},
-		{
-			name: "Test 4: Get Dummy",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-			},
-			needle:   net.NewPfx(strAddr("10.0.0.0"), 7),
-			expected: nil,
-		},
-		{
-			name: "Test 5",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 10), nil),
-			},
-			needle: net.NewPfx(strAddr("11.100.123.0"), 24),
-			expected: []*Route{
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-			},
-		},
-		{
-			name: "Test 4: Get nonexistent #1",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("11.100.123.0"), 24), nil),
-			},
-			needle:   net.NewPfx(strAddr("10.0.0.0"), 10),
-			expected: nil,
-		},
-		{
-			name: "Test 4: Get nonexistent #2",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 12), nil),
-			},
-			needle:   net.NewPfx(strAddr("10.0.0.0"), 10),
-			expected: nil,
-		},
-	}
-
-	for _, test := range tests {
-		rt := New(false)
-		for _, route := range test.routes {
-			rt.AddPath(route)
-		}
-		p := rt.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 TestInsert(t *testing.T) {
-	tests := []struct {
-		name     string
-		routes   []*Route
-		expected *node
-	}{
-		{
-			name: "Insert first node",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-			},
-			expected: &node{
-				route: &Route{
-					pfx: net.NewPfx(strAddr("10.0.0.0"), 8),
-				},
-				skip: 8,
-			},
-		},
-		{
-			name: "Insert duplicate node",
-			routes: []*Route{
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-				NewRoute(net.NewPfx(strAddr("10.0.0.0"), 8), nil),
-			},
-			expected: &node{
-				route: &Route{
-					pfx: net.NewPfx(strAddr("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 {
-		rt := New(false)
-		for _, route := range test.routes {
-			rt.AddPath(route)
-		}
-
-		assert.Equal(t, test.expected, rt.root)
-	}
-}
-
-func strAddr(s string) uint32 {
-	ret, _ := net.StrToAddr(s)
-	return ret
-}
diff --git a/rt/static.go b/rt/static.go
deleted file mode 100644
index ae3e6bc35ea659c229f4ea8b960bc24a47f42275..0000000000000000000000000000000000000000
--- a/rt/static.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package rt
-
-type StaticPath struct {
-	NextHop uint32
-}
-
-func (r *Route) staticPathSelection() (best *Path, active []*Path) {
-	if r.paths == nil {
-		return nil, nil
-	}
-
-	if len(r.paths) == 0 {
-		return nil, nil
-	}
-
-	for _, p := range r.paths {
-		if p.Type != StaticPathType {
-			continue
-		}
-
-		active = append(active, p)
-		best = p
-	}
-
-	return
-}