diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1e50ce1fe049a730dec90379d334ca7fefa26602..0000000000000000000000000000000000000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.raw filter=lfs diff=lfs merge=lfs -text
diff --git a/README.md b/README.md
index f1b3a350b4dc2f75a449cd002a3b67dc91fdbd5c..0e5c3465a667fc4a961fe719f63c12c7eb9811a4 100644
--- a/README.md
+++ b/README.md
@@ -13,20 +13,34 @@ A re-implementation of BGP, IS-IS and OSPF in go. We value respect and robustnes
 
 #### BGP
 
-    cd examples/bgp/ && go build
+```
+cd examples/bgp/ && go build
+```
 
 #### BMP
 
-    cd examples/bmp/ && go build
+```
+cd examples/bmp/ && go build
+```
 
 #### Device
 
-    cd examples/device && go build
+```
+cd examples/device && go build
+```
 
 ### Run Tests
 
-    go test -v -cover ./...
+```
+go test -v -cover ./...
+```
 
 ### Update modules
 
-    go mod tidy
+```
+go mod tidy
+```
+
+## Benchmarks
+
+The benchmarks can be found in the [bio-rd-benchmarks](/bio-routing/bio-rd-benchmarks) repository.
\ No newline at end of file
diff --git a/benchmarks/bgp/decode_real_full_feed/AS8881.raw b/benchmarks/bgp/decode_real_full_feed/AS8881.raw
deleted file mode 100644
index a1249d5cca0270b3ad5fae344fcfce64504a423f..0000000000000000000000000000000000000000
--- a/benchmarks/bgp/decode_real_full_feed/AS8881.raw
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:f3881daddbdef448f52c50cbb6fd93d0d677d2d3c45816f69bb2d0ddc5d0f506
-size 12282584
diff --git a/benchmarks/bgp/decode_real_full_feed/main.go b/benchmarks/bgp/decode_real_full_feed/main.go
deleted file mode 100644
index acd99cb9687717e21aec96fae9511ebbfe17a809..0000000000000000000000000000000000000000
--- a/benchmarks/bgp/decode_real_full_feed/main.go
+++ /dev/null
@@ -1,144 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"flag"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"runtime/pprof"
-	"time"
-
-	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-
-	log "github.com/sirupsen/logrus"
-)
-
-var (
-	nRuns = flag.Int("runs", 1, "# runs")
-)
-
-type task struct {
-	num int
-	raw *bytes.Buffer
-	msg *packet.BGPMessage
-}
-
-func main() {
-	flag.Parse()
-
-	updates := make([][]*bytes.Buffer, *nRuns)
-	for i := 0; i < *nRuns; i++ {
-		updates[i] = make([]*bytes.Buffer, 0)
-	}
-
-	raw, err := ioutil.ReadFile("AS8881.raw")
-	if err != nil {
-		log.Errorf("Unable to open PCAP file: %v", err)
-		os.Exit(1)
-	}
-
-	msgs := extractBGPMessages(raw)
-	for _, msg := range msgs {
-		for i := 0; i < *nRuns; i++ {
-			updates[i] = append(updates[i], bytes.NewBuffer(msg))
-		}
-	}
-
-	c := len(updates[0])
-
-	fmt.Printf("Decoding %d BGP messages\n", c)
-
-	buf := bytes.NewBuffer(nil)
-	err = pprof.StartCPUProfile(buf)
-	if err != nil {
-		panic(err)
-	}
-
-	dco := &packet.DecodeOptions{
-		Use32BitASN: true,
-	}
-
-	start := time.Now().UnixNano()
-
-	nlriCount := 0
-	for j := 0; j < *nRuns; j++ {
-		for i := 0; i < c; i++ {
-			msg, err := packet.Decode(updates[j][i], dco)
-			if err != nil {
-				fmt.Printf("Unable to decode msg %d: %v\n", i, err)
-				continue
-			}
-
-			if msg.Header.Type == 2 {
-				n := msg.Body.(*packet.BGPUpdate).NLRI
-				for {
-					if n == nil {
-						break
-					}
-
-					nlriCount++
-
-					n = n.Next
-				}
-			}
-		}
-	}
-	fmt.Printf("NLRIs: %d\n", nlriCount)
-
-	end := time.Now().UnixNano()
-
-	d := end - start
-	pprof.StopCPUProfile()
-	fmt.Printf("decoding updates took %d ms\n", d/1000000)
-
-	ioutil.WriteFile("profile.pprof", buf.Bytes(), 0644)
-
-	x := bytes.NewBuffer(nil)
-	pprof.WriteHeapProfile(x)
-
-	ioutil.WriteFile("heap.pprof", x.Bytes(), 0644)
-}
-
-func hexDump(input []byte) string {
-	s := ""
-	for _, x := range input {
-		s += fmt.Sprintf("%x ", x)
-	}
-
-	return s
-}
-
-func extractBGPMessages(input []byte) [][]byte {
-	fmt.Printf("Extracting BGP messages from %d bytes\n", len(input))
-	ret := make([][]byte, 0)
-
-	//fmt.Printf("Data: %v\n", input[0:24])
-	l := len(input)
-	i := 0
-	for {
-		if i+17 > l {
-			break
-		}
-
-		for j := 0; j < 16; j++ {
-			if input[i+j] != 255 {
-				panic(fmt.Sprintf("Invalid BGP marker: (%d+%d=%d): %s", i, j, i+j, hexDump(input[i:i+16])))
-			}
-		}
-
-		msgLen := uint16(input[i+16])*256 + uint16(input[i+17])
-
-		ret = append(ret, input[i:i+int(msgLen)])
-
-		if msgLen == 0 {
-			panic(msgLen)
-		}
-
-		i += int(msgLen)
-	}
-
-	fmt.Printf("Done\n")
-
-	return ret
-}
diff --git a/benchmarks/bgp/learning/main.go b/benchmarks/bgp/learning/main.go
deleted file mode 100644
index 814dbbbb1fcfece734c56b81dc5d1eb5ad7ac451..0000000000000000000000000000000000000000
--- a/benchmarks/bgp/learning/main.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"runtime/pprof"
-	"time"
-
-	"net/http"
-	_ "net/http/pprof"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/bio-routing/bio-rd/protocols/bgp/server"
-	"github.com/bio-routing/bio-rd/routingtable"
-	"github.com/bio-routing/bio-rd/routingtable/filter"
-	"github.com/bio-routing/bio-rd/routingtable/vrf"
-	btesting "github.com/bio-routing/bio-rd/testing"
-	"github.com/sirupsen/logrus"
-)
-
-/*
-*
-* This benchmark measure the time to learn 750k BGP prefixes
-*
- */
-
-func main() {
-	go http.ListenAndServe("localhost:1337", nil)
-
-	b := server.NewBGPServer(100, nil)
-	v, err := vrf.New("master", 0)
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	iEnd := 100
-	jEnd := 100
-	kEnd := 75
-
-	ch := make(chan struct{})
-	fmt.Printf("Learning %d routes\n", kEnd*iEnd*jEnd)
-	v.IPv4UnicastRIB().SetCountTarget(uint64(kEnd*iEnd*jEnd), ch)
-
-	err = b.Start()
-	if err != nil {
-		logrus.Fatalf("Unable to start BGP server: %v", err)
-	}
-
-	con := btesting.NewMockConnBidi(&btesting.MockAddr{
-		Addr:  "169.254.200.0:1234",
-		Proto: "TCP",
-	}, &btesting.MockAddr{
-		Addr:  "172.17.0.3:179",
-		Proto: "TCP",
-	})
-
-	openMSG := []byte{
-		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
-		0, 29, // Length
-		1,      // Type = Open
-		4,      // Version
-		0, 200, //ASN,
-		0, 15, // Holdtime
-		10, 20, 30, 40, // BGP Identifier
-		0, // Opt Parm Len
-	}
-	con.WriteB(openMSG)
-
-	keepAlive := []byte{
-		255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
-		0, 19, // Length
-		4, // Type = Keepalive
-	}
-	con.WriteB(keepAlive)
-
-	c := 0
-	for i := 0; i < iEnd; i++ {
-		for j := 0; j < jEnd; j++ {
-			for k := 1; k <= kEnd; k++ {
-				update := []byte{
-					255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Marker
-					0, 80, // Length
-					2, // Type = Update
-
-					0, 0, // Withdraw length
-					0, 53, // Total Path Attribute Length
-
-					255,  // Attribute flags
-					1,    // Attribute Type code (ORIGIN)
-					0, 1, // Length
-					2, // INCOMPLETE
-
-					0,      // Attribute flags
-					2,      // Attribute Type code (AS Path)
-					12,     // Length
-					2,      // Type = AS_SEQUENCE
-					2,      // Path Segment Length
-					59, 65, // AS15169
-					12, 248, // AS3320
-					1,      // Type = AS_SET
-					2,      // Path Segment Length
-					59, 65, // AS15169
-					12, 248, // AS3320
-
-					0,              // Attribute flags
-					3,              // Attribute Type code (Next Hop)
-					4,              // Length
-					10, 11, 12, 13, // Next Hop
-
-					0,          // Attribute flags
-					4,          // Attribute Type code (MED)
-					4,          // Length
-					0, 0, 1, 0, // MED 256
-
-					0,          // Attribute flags
-					5,          // Attribute Type code (Local Pref)
-					4,          // Length
-					0, 0, 1, 0, // Local Pref 256
-
-					0, // Attribute flags
-					6, // Attribute Type code (Atomic Aggregate)
-					0, // Length
-
-					0,    // Attribute flags
-					7,    // Attribute Type code (Atomic Aggregate)
-					6,    // Length
-					1, 2, // ASN
-					10, 11, 12, 13, // Address
-
-					24, uint8(k), uint8(i), uint8(j), // Prefix
-				}
-				con.WriteB(update)
-				c++
-			}
-		}
-	}
-
-	fmt.Printf("Added routes: %d\n", c)
-
-	buf := bytes.NewBuffer(nil)
-	err = pprof.StartCPUProfile(buf)
-	if err != nil {
-		panic(err)
-	}
-
-	peerCfg := server.PeerConfig{
-		AdminEnabled:      true,
-		LocalAS:           65200,
-		PeerAS:            200,
-		PeerAddress:       bnet.IPv4FromOctets(172, 17, 0, 3).Ptr(),
-		LocalAddress:      bnet.IPv4FromOctets(169, 254, 200, 0).Ptr(),
-		ReconnectInterval: time.Second * 15,
-		HoldTime:          time.Second * 90,
-		KeepAlive:         time.Second * 30,
-		Passive:           true,
-		RouterID:          b.RouterID(),
-		IPv4: &server.AddressFamilyConfig{
-			ImportFilterChain: filter.NewAcceptAllFilterChain(),
-			ExportFilterChain: filter.NewAcceptAllFilterChain(),
-			AddPathSend: routingtable.ClientOptions{
-				MaxPaths: 10,
-			},
-		},
-		RouteServerClient: true,
-		VRF:               v,
-	}
-
-	b.AddPeer(peerCfg)
-
-	start := time.Now().UnixNano()
-	b.ConnectMockPeer(peerCfg, con)
-
-	<-ch
-	end := time.Now().UnixNano()
-
-	d := end - start
-	pprof.StopCPUProfile()
-	fmt.Printf("Learning routes took %d ms\n", d/1000000)
-
-	ioutil.WriteFile("profile.pprof", buf.Bytes(), 0644)
-
-	x := bytes.NewBuffer(nil)
-	pprof.WriteHeapProfile(x)
-
-	ioutil.WriteFile("heap.pprof", x.Bytes(), 0644)
-}
diff --git a/benchmarks/ipcache/main.go b/benchmarks/ipcache/main.go
deleted file mode 100644
index 8bde991cf59839a31e54c6079aea5fb1d973f9e7..0000000000000000000000000000000000000000
--- a/benchmarks/ipcache/main.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"fmt"
-	"io/ioutil"
-	"runtime/pprof"
-	"time"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-)
-
-func main() {
-	for i := 0; i < 255; i++ {
-		for j := 0; j < 255; j++ {
-			for k := 0; k < 11; k++ {
-				addr := bnet.IPv4FromOctets(10, uint8(i), uint8(j), uint8(k))
-				addr.Dedup()
-			}
-		}
-	}
-
-	buf := bytes.NewBuffer(nil)
-	err := pprof.StartCPUProfile(buf)
-	if err != nil {
-		panic(err)
-	}
-
-	start := time.Now().UnixNano()
-
-	for x := 0; x < 1; x++ {
-		for i := 0; i < 255; i++ {
-			for j := 0; j < 255; j++ {
-				for k := 0; k < 11; k++ {
-					addr := bnet.IPv4FromOctets(10, uint8(i), uint8(j), uint8(k))
-					addr.Dedup()
-				}
-			}
-		}
-	}
-
-	end := time.Now().UnixNano()
-
-	d := end - start
-	pprof.StopCPUProfile()
-	fmt.Printf("Looking up IP-Addresses took %d ms\n", d/1000000)
-
-	ioutil.WriteFile("profile.pprof", buf.Bytes(), 0644)
-
-	x := bytes.NewBuffer(nil)
-	pprof.WriteHeapProfile(x)
-
-	ioutil.WriteFile("heap.pprof", x.Bytes(), 0644)
-}
diff --git a/benchmarks/pfxcache/main.go b/benchmarks/pfxcache/main.go
deleted file mode 100644
index d40958e70548e94aed8617247656deb7c40ab5a9..0000000000000000000000000000000000000000
--- a/benchmarks/pfxcache/main.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package main
-
-import (
-	"bytes"
-	"fmt"
-	"io/ioutil"
-	"runtime/pprof"
-	"time"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-)
-
-func main() {
-	pfxs := make([]*bnet.Prefix, 0)
-	for i := 0; i < 255; i++ {
-		for j := 0; j < 255; j++ {
-			for k := 0; k < 11; k++ {
-				addr := bnet.IPv4FromOctets(uint8(k)+1, uint8(i), uint8(j), 0)
-
-				pfxs = append(pfxs, bnet.NewPfx(addr, 24).Dedup())
-			}
-		}
-	}
-
-	buf := bytes.NewBuffer(nil)
-	err := pprof.StartCPUProfile(buf)
-	if err != nil {
-		panic(err)
-	}
-
-	start := time.Now().UnixNano()
-
-	for i := range pfxs {
-		pfxs[i].Dedup()
-	}
-
-	end := time.Now().UnixNano()
-
-	d := end - start
-	pprof.StopCPUProfile()
-	fmt.Printf("Looking up Prefixes took %d ms\n", d/1000000)
-
-	ioutil.WriteFile("profile.pprof", buf.Bytes(), 0644)
-
-	x := bytes.NewBuffer(nil)
-	pprof.WriteHeapProfile(x)
-
-	ioutil.WriteFile("heap.pprof", x.Bytes(), 0644)
-}