diff --git a/examples/netlink/main.go b/examples/fib/main.go
similarity index 89%
rename from examples/netlink/main.go
rename to examples/fib/main.go
index aa4e493acb4e37c1f2745f5593e39811870ecacc..677ab11574f6b4e2afd037bc2d33b5f8f8b8f73b 100644
--- a/examples/netlink/main.go
+++ b/examples/fib/main.go
@@ -7,7 +7,7 @@ import (
 
 	"github.com/bio-routing/bio-rd/config"
 	"github.com/bio-routing/bio-rd/protocols/bgp/server"
-	"github.com/bio-routing/bio-rd/protocols/netlink"
+	"github.com/bio-routing/bio-rd/protocols/fib"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 	log "github.com/sirupsen/logrus"
 
@@ -43,8 +43,8 @@ func main() {
 	b := server.NewBgpServer()
 	startBGPServer(b, rib, cfg)
 
-	// Netlink communication
-	n := protocolnetlink.NewNetlink(&config.Netlink{
+	// FIB communication
+	n := fib.NewFIB(&config.Netlink{
 		HoldTime:       time.Second * 15,
 		UpdateInterval: time.Second * 15,
 		RoutingTable:   config.RtMain,
diff --git a/examples/netlink/main_ipv4.go b/examples/fib/main_ipv4.go
similarity index 100%
rename from examples/netlink/main_ipv4.go
rename to examples/fib/main_ipv4.go
diff --git a/examples/netlink/main_ipv6.go b/examples/fib/main_ipv6.go
similarity index 100%
rename from examples/netlink/main_ipv6.go
rename to examples/fib/main_ipv6.go
diff --git a/go.mod b/go.mod
index ef129af356ca82c3dc7489c13b381b63d2e13bbf..4a127d313e57dbab42d096521192f261a995393a 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/vishvananda/netlink v1.0.0
 	github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect
 	golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect
-	golang.org/x/net v0.0.0-20181220203305-927f97764cc3 // indirect
+	golang.org/x/net v0.0.0-20181220203305-927f97764cc3
 	golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 // indirect
 	golang.org/x/sys v0.0.0-20181228120256-c6cbdbf9e68a // indirect
 	google.golang.org/genproto v0.0.0-20181221175505-bd9b4fb69e2f // indirect
diff --git a/protocols/device/server_darwin.go b/protocols/device/server_darwin.go
index 803b9a1a7420f87f09ef33443f3e57af49242ed3..776fcd734b1f0159a4bba88c3e2e6852a0a3d2a6 100644
--- a/protocols/device/server_darwin.go
+++ b/protocols/device/server_darwin.go
@@ -7,9 +7,9 @@ import (
 )
 
 func (ds *Server) loadAdapter() error {
-	a, err := newOSAdapterLinux(ds)
+	a, err := newOSAdapterDarwin(ds)
 	if err != nil {
-		return errors.Wrap(err, "Unable to create linux adapter")
+		return errors.Wrap(err, "Unable to create OS X adapter")
 	}
 
 	ds.osAdapter = a
@@ -19,7 +19,7 @@ func (ds *Server) loadAdapter() error {
 type osAdapterDarwin struct {
 }
 
-func newOSAdapterLinux(srv *Server) (*osAdapterDarwin, error) {
+func newOSAdapterDarwin(srv *Server) (*osAdapterDarwin, error) {
 	return nil, fmt.Errorf("Not implemented")
 }
 
diff --git a/protocols/fib/fib.go b/protocols/fib/fib.go
new file mode 100644
index 0000000000000000000000000000000000000000..a1b64fe25ad082928fd4156937476f303336dd80
--- /dev/null
+++ b/protocols/fib/fib.go
@@ -0,0 +1,44 @@
+package fib
+
+import (
+	"github.com/bio-routing/bio-rd/config"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+)
+
+// FIB is forwarding information base
+type FIB struct {
+	locRib *locRIB.LocRIB
+
+	//writer *NetlinkWriter
+	//reader *NetlinkReader
+}
+
+// NewFIB creates a new Netlink object and returns the pointer to it
+func NewFIB(options *config.Netlink, locRib *locRIB.LocRIB) *FIB {
+
+	n := &FIB{
+		locRib: locRib,
+		//writer: NewNetlinkWriter(options),
+		//reader: NewNetlinkReader(options),
+	}
+	return n
+}
+
+// Start the Netlink module
+func (f *FIB) Start() {
+	// connect all RIBs
+	/*options := routingtable.ClientOptions{
+		BestOnly: false,
+		EcmpOnly: false,
+		MaxPaths: ^uint(0), // max int
+	}*/
+
+	// 1. from locRib to Kernel
+	//f.locRib.RegisterWithOptions(n.writer, options)
+
+	// 2. from Kernel to locRib
+	//f.reader.clientManager.RegisterWithOptions(n.locRib, options)
+
+	// Listen for new routes from kernel
+	//go n.reader.Read()
+}
diff --git a/protocols/fib/fib_linux.go b/protocols/fib/fib_linux.go
new file mode 100644
index 0000000000000000000000000000000000000000..85c98f69c2ac9f19feae0c2a3389555e82f2cca4
--- /dev/null
+++ b/protocols/fib/fib_linux.go
@@ -0,0 +1,138 @@
+package fib
+
+import (
+	"fmt"
+
+	bnet "github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/vishvananda/netlink"
+)
+
+const (
+	ProtoUnspec   = 0  // unspec (from /etc/iproute2/rt_protos)
+	ProtoRedirect = 1  // redirect (from /etc/iproute2/rt_protos)
+	ProtoKernel   = 2  // kernel (from /etc/iproute2/rt_protos)
+	ProtoBoot     = 3  // boot (from /etc/iproute2/rt_protos)
+	ProtoStatic   = 4  // static (from /etc/iproute2/rt_protos)
+	ProtoZebra    = 11 // zebra (from /etc/iproute2/rt_protos)
+	ProtoBird     = 12 // bird (from /etc/iproute2/rt_protos)
+	ProtoDHCP     = 16 // dhcp (from /etc/iproute2/rt_protos)
+	ProtoBio      = 45 // bio
+)
+
+// NetlinkRouteDiff gets the list of elements contained by a but not b
+func NetlinkRouteDiff(a, b []netlink.Route) []netlink.Route {
+	ret := make([]netlink.Route, 0)
+
+	for _, pa := range a {
+		if !netlinkRoutesContains(pa, b) {
+			ret = append(ret, pa)
+		}
+	}
+
+	return ret
+}
+
+func netlinkRoutesContains(needle netlink.Route, haystack []netlink.Route) bool {
+	for i := range haystack {
+		if netlinkRouteEquals(&needle, &haystack[i]) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func netlinkRouteEquals(a, b *netlink.Route) bool {
+	aMaskSize, aMaskBits := a.Dst.Mask.Size()
+	bMaskSize, bMaskBits := b.Dst.Mask.Size()
+
+	return a.LinkIndex == b.LinkIndex &&
+		a.ILinkIndex == b.ILinkIndex &&
+		a.Scope == b.Scope &&
+
+		a.Dst.IP.Equal(b.Dst.IP) &&
+		aMaskSize == bMaskSize &&
+		aMaskBits == bMaskBits &&
+
+		a.Src.Equal(b.Src) &&
+		a.Gw.Equal(b.Gw) &&
+
+		a.Protocol == b.Protocol &&
+		a.Priority == b.Priority &&
+		a.Table == b.Table &&
+		a.Type == b.Type &&
+		a.Tos == b.Tos &&
+		a.Flags == b.Flags &&
+		a.MTU == b.MTU &&
+		a.AdvMSS == b.AdvMSS
+}
+
+// NewNlPathFromRoute creates a new route.FIBPath object from a netlink.Route object
+func NewPathsFromNlRoute(r netlink.Route, kernel bool) (bnet.Prefix, []*route.Path, error) {
+	var src bnet.IP
+	var dst bnet.Prefix
+
+	if r.Src == nil && r.Dst == nil {
+		return bnet.Prefix{}, nil, fmt.Errorf("Cannot create NlPath, since source and destination are both nil")
+	}
+
+	if r.Src == nil && r.Dst != nil {
+		dst = bnet.NewPfxFromIPNet(r.Dst)
+		if dst.Addr().IsIPv4() {
+			src = bnet.IPv4(0)
+		} else {
+			src = bnet.IPv6(0, 0)
+		}
+	}
+
+	if r.Src != nil && r.Dst == nil {
+		src, _ = bnet.IPFromBytes(r.Src)
+		if src.IsIPv4() {
+			dst = bnet.NewPfx(bnet.IPv4(0), 0)
+		} else {
+			dst = bnet.NewPfx(bnet.IPv6(0, 0), 0)
+		}
+	}
+
+	if r.Src != nil && r.Dst != nil {
+		src, _ = bnet.IPFromBytes(r.Src)
+		dst = bnet.NewPfxFromIPNet(r.Dst)
+	}
+
+	paths := make([]*route.Path, 0)
+
+	if len(r.MultiPath) > 0 {
+		for _, multiPath := range r.MultiPath {
+			nextHop, _ := bnet.IPFromBytes(multiPath.Gw)
+			paths = append(paths, &route.Path{
+				Type: route.FIBPathType,
+				FIBPath: &route.FIBPath{
+					Src:      src,
+					NextHop:  nextHop,
+					Priority: r.Priority,
+					Protocol: r.Protocol,
+					Type:     r.Type,
+					Table:    r.Table,
+					Kernel:   kernel,
+				},
+			})
+		}
+	} else {
+		nextHop, _ := bnet.IPFromBytes(r.Gw)
+		paths = append(paths, &route.Path{
+			Type: route.FIBPathType,
+			FIBPath: &route.FIBPath{
+				Src:      src,
+				NextHop:  nextHop,
+				Priority: r.Priority,
+				Protocol: r.Protocol,
+				Type:     r.Type,
+				Table:    r.Table,
+				Kernel:   kernel,
+			},
+		})
+	}
+
+	return dst, paths, nil
+}
diff --git a/protocols/fib/fib_linux_test.go b/protocols/fib/fib_linux_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..64b4ad237848c64cdb7e5d154316d0adec676d15
--- /dev/null
+++ b/protocols/fib/fib_linux_test.go
@@ -0,0 +1,393 @@
+package fib
+
+import (
+	"net"
+	"testing"
+
+	bnet "github.com/bio-routing/bio-rd/net"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/stretchr/testify/assert"
+	"github.com/vishvananda/netlink"
+)
+
+func TestNetlinkRouteDiff(t *testing.T) {
+	tests := []struct {
+		name     string
+		left     []netlink.Route
+		right    []netlink.Route
+		expected []netlink.Route
+	}{
+		{
+			name: "Equal",
+			left: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+			right: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+			expected: []netlink.Route{},
+		}, {
+			name: "Left empty",
+			left: []netlink.Route{},
+			right: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+			expected: []netlink.Route{},
+		}, {
+			name: "Right empty",
+			left: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+			right: []netlink.Route{},
+			expected: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+		}, {
+			name: "Diff",
+			left: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+			right: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(10, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 1,
+				},
+			},
+			expected: []netlink.Route{
+				{
+					Dst: &net.IPNet{
+						IP:   net.IPv4(20, 0, 0, 1),
+						Mask: net.IPv4Mask(255, 0, 0, 0),
+					},
+					Table: 2,
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res := NetlinkRouteDiff(test.left, test.right)
+		assert.Equal(t, test.expected, res)
+	}
+
+}
+
+func TestNewPathsFromNetlinkRoute(t *testing.T) {
+	tests := []struct {
+		name          string
+		source        netlink.Route
+		expectedPfx   bnet.Prefix
+		expectedPaths []*route.Path
+		expectError   bool
+	}{
+		{
+			name: "Simple",
+			source: netlink.Route{
+				Dst:      bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
+				Src:      bnet.IPv4(456).Bytes(),
+				Gw:       bnet.IPv4(789).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv4(456),
+						NextHop:  bnet.IPv4(789),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "Multiple nexthop",
+			source: netlink.Route{
+				Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
+				Src: bnet.IPv4(456).Bytes(),
+				MultiPath: []*netlink.NexthopInfo{
+					{
+						LinkIndex: 1,
+						Hops:      1,
+						Gw:        bnet.IPv4(123).Bytes(),
+						Flags:     0,
+						NewDst:    nil,
+						Encap:     nil,
+					}, {
+						LinkIndex: 2,
+						Hops:      1,
+						Gw:        bnet.IPv4(345).Bytes(),
+						Flags:     0,
+						NewDst:    nil,
+						Encap:     nil,
+					},
+				},
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv4(456),
+						NextHop:  bnet.IPv4(123),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				}, {
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv4(456),
+						NextHop:  bnet.IPv4(345),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "No source but destination",
+			source: netlink.Route{
+				Dst:      bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
+				Gw:       bnet.IPv4(789).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv4(0),
+						NextHop:  bnet.IPv4(789),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "Source but no destination",
+			source: netlink.Route{
+				Src:      bnet.IPv4(456).Bytes(),
+				Gw:       bnet.IPv4(789).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(0, 0, 0, 0), 0),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv4(456),
+						NextHop:  bnet.IPv4(789),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "No source but no destination",
+			source: netlink.Route{
+				Gw:       bnet.IPv4(789).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx:   bnet.Prefix{},
+			expectedPaths: []*route.Path{},
+			expectError:   true,
+		},
+		{
+			name: "No source but destination IPv6",
+			source: netlink.Route{
+				Dst:      bnet.NewPfx(bnet.IPv6(2001, 0), 48).GetIPNet(),
+				Gw:       bnet.IPv6(2001, 123).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv6(2001, 0), 48),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv6(0, 0),
+						NextHop:  bnet.IPv6(2001, 123),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "Source but no destination IPv6",
+			source: netlink.Route{
+				Src:      bnet.IPv6(2001, 456).Bytes(),
+				Gw:       bnet.IPv6(2001, 789).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx: bnet.NewPfx(bnet.IPv6(0, 0), 0),
+			expectedPaths: []*route.Path{
+				{
+					Type: route.FIBPathType,
+					FIBPath: &route.FIBPath{
+						Src:      bnet.IPv6(2001, 456),
+						NextHop:  bnet.IPv6(2001, 789),
+						Protocol: ProtoKernel,
+						Priority: 1,
+						Table:    254,
+						Type:     1,
+						Kernel:   true,
+					},
+				},
+			},
+			expectError: false,
+		},
+		{
+			name: "no source no destination",
+			source: netlink.Route{
+				Gw:       bnet.IPv4(123).Bytes(),
+				Protocol: ProtoKernel,
+				Priority: 1,
+				Table:    254,
+				Type:     1,
+			},
+			expectedPfx:   bnet.NewPfx(bnet.IPv4(0), 0),
+			expectedPaths: []*route.Path{{}},
+			expectError:   true,
+		},
+	}
+
+	for _, test := range tests {
+		pfx, paths, err := NewPathsFromNlRoute(test.source, true)
+		if test.expectError {
+			assert.Error(t, err)
+		} else {
+			assert.NoError(t, err)
+			assert.Equalf(t, test.expectedPaths, paths, test.name)
+			assert.Equalf(t, test.expectedPfx, pfx, test.name)
+		}
+	}
+}
diff --git a/protocols/netlink/netlink_reader.go b/protocols/fib/reader_linux.go
similarity index 94%
rename from protocols/netlink/netlink_reader.go
rename to protocols/fib/reader_linux.go
index 20e4b12bdcf66739b8738c5b0fade165d92c7b0b..23df0d9882439fb6cb2c5f1fcc095a48f26973cd 100644
--- a/protocols/netlink/netlink_reader.go
+++ b/protocols/fib/reader_linux.go
@@ -1,4 +1,4 @@
-package protocolnetlink
+package fib
 
 import (
 	"fmt"
@@ -59,7 +59,7 @@ func (nr *NetlinkReader) Read() {
 		nr.mu.Lock()
 		nr.routes = routes
 
-		log.Debugf("NetlinkRouteDiff: %d", len(route.NetlinkRouteDiff(nr.routes, routes)))
+		log.Debugf("NetlinkRouteDiff: %d", len(NetlinkRouteDiff(nr.routes, routes)))
 		nr.mu.Unlock()
 
 		time.Sleep(nr.options.UpdateInterval)
@@ -81,7 +81,7 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) {
 
 	// only advertise changed routes
 	nr.mu.RLock()
-	advertise := route.NetlinkRouteDiff(routes, nr.routes)
+	advertise := NetlinkRouteDiff(routes, nr.routes)
 	nr.mu.RUnlock()
 
 	for _, client := range nr.clientManager.Clients() {
@@ -92,7 +92,7 @@ func (nr *NetlinkReader) addPathsToClients(routes []netlink.Route) {
 			}
 
 			// create pfx and path from route
-			pfx, paths, err := route.NewPathsFromNlRoute(r, true)
+			pfx, paths, err := NewPathsFromNlRoute(r, true)
 			if err != nil {
 				log.WithError(err).WithFields(log.Fields{
 					"prefix": pfx.String(),
@@ -135,7 +135,7 @@ func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) {
 	}
 
 	// only withdraw changed routes
-	withdraw := route.NetlinkRouteDiff(nr.routes, routes)
+	withdraw := NetlinkRouteDiff(nr.routes, routes)
 	nr.mu.RUnlock()
 
 	for _, client := range nr.clientManager.Clients() {
@@ -146,7 +146,7 @@ func (nr *NetlinkReader) removePathsFromClients(routes []netlink.Route) {
 			}
 
 			// create pfx and path from route
-			pfx, paths, err := route.NewPathsFromNlRoute(r, true)
+			pfx, paths, err := NewPathsFromNlRoute(r, true)
 			if err != nil {
 				log.WithError(err).WithFields(log.Fields{
 					"prefix": pfx.String(),
diff --git a/protocols/netlink/netlink_writer.go b/protocols/fib/writer_linux.go
similarity index 99%
rename from protocols/netlink/netlink_writer.go
rename to protocols/fib/writer_linux.go
index fae9a1fdd78a6b7285213fb3984fd7bb2c7532d0..c5fac76b3ca8a3761da2f0f0a5cf4d9ed104ae44 100644
--- a/protocols/netlink/netlink_writer.go
+++ b/protocols/fib/writer_linux.go
@@ -1,4 +1,4 @@
-package protocolnetlink
+package fib
 
 import (
 	"fmt"
diff --git a/protocols/netlink/netlink.go b/protocols/netlink/netlink.go
deleted file mode 100644
index 62ce9449a526fa67deba3647c3a33532f637ef69..0000000000000000000000000000000000000000
--- a/protocols/netlink/netlink.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package protocolnetlink
-
-import (
-	"github.com/bio-routing/bio-rd/config"
-	"github.com/bio-routing/bio-rd/routingtable"
-	"github.com/bio-routing/bio-rd/routingtable/locRIB"
-)
-
-// Netlink is the netlink module which handles the entire NetlinkCommunication
-type Netlink struct {
-	locRib *locRIB.LocRIB
-
-	writer *NetlinkWriter
-	reader *NetlinkReader
-}
-
-// NewNetlink creates a new Netlink object and returns the pointer to it
-func NewNetlink(options *config.Netlink, locRib *locRIB.LocRIB) *Netlink {
-
-	n := &Netlink{
-		locRib: locRib,
-		writer: NewNetlinkWriter(options),
-		reader: NewNetlinkReader(options),
-	}
-	return n
-}
-
-// Start the Netlink module
-func (n *Netlink) Start() {
-	// connect all RIBs
-	options := routingtable.ClientOptions{
-		BestOnly: false,
-		EcmpOnly: false,
-		MaxPaths: ^uint(0), // max int
-	}
-
-	// 1. from locRib to Kernel
-	n.locRib.RegisterWithOptions(n.writer, options)
-
-	// 2. from Kernel to locRib
-	n.reader.clientManager.RegisterWithOptions(n.locRib, options)
-
-	// Listen for new routes from kernel
-	go n.reader.Read()
-}
diff --git a/route/fib_path.go b/route/fib_path.go
new file mode 100644
index 0000000000000000000000000000000000000000..a43d91cd370214940cbfa2d89be43b9e40597a20
--- /dev/null
+++ b/route/fib_path.go
@@ -0,0 +1,114 @@
+package route
+
+import (
+	"fmt"
+
+	bnet "github.com/bio-routing/bio-rd/net"
+)
+
+const (
+	ProtoBio = 45 // bio
+)
+
+// FIBPath represents a path learned via Netlink of a route
+type FIBPath struct {
+	Src      bnet.IP
+	NextHop  bnet.IP // GW
+	Priority int
+	Protocol int
+	Type     int
+	Table    int
+	Kernel   bool // True if the route is already installed in the kernel
+}
+
+// NewNlPathFromBgpPath creates a new FIBPath object from a BGPPath object
+func NewNlPathFromBgpPath(p *BGPPath) *FIBPath {
+	return &FIBPath{
+		Src:      p.Source,
+		NextHop:  p.NextHop,
+		Protocol: ProtoBio,
+		Kernel:   false,
+	}
+}
+
+// Select compares s with t and returns negative if s < t, 0 if paths are equal, positive if s > t
+func (s *FIBPath) Select(t *FIBPath) int8 {
+	if s.NextHop.Compare(t.NextHop) < 0 {
+		return -1
+	}
+
+	if s.NextHop.Compare(t.NextHop) > 0 {
+		return 1
+	}
+
+	if s.Src.Compare(t.Src) < 0 {
+		return -1
+	}
+
+	if s.Src.Compare(t.Src) > 0 {
+		return 1
+	}
+
+	if s.Priority < t.Priority {
+		return -1
+	}
+
+	if s.Priority > t.Priority {
+		return 1
+	}
+
+	if s.Protocol < t.Protocol {
+		return -1
+	}
+
+	if s.Protocol > t.Protocol {
+		return 1
+	}
+
+	if s.Table < t.Table {
+		return -1
+	}
+
+	if s.Table > t.Table {
+		return 1
+	}
+
+	return 0
+}
+
+// ECMP determines if path s and t are equal in terms of ECMP
+func (s *FIBPath) ECMP(t *FIBPath) bool {
+	return s.Src == t.Src && s.Priority == t.Priority && s.Protocol == t.Protocol && s.Type == t.Type && s.Table == t.Table
+}
+
+// Copy duplicates the current object
+func (s *FIBPath) Copy() *FIBPath {
+	if s == nil {
+		return nil
+	}
+
+	cp := *s
+	return &cp
+}
+
+// Print all known information about a route in logfile friendly format
+func (s *FIBPath) String() string {
+	ret := fmt.Sprintf("Source: %s, ", s.Src.String())
+	ret += fmt.Sprintf("NextHop: %s, ", s.NextHop.String())
+	ret += fmt.Sprintf("Priority: %d, ", s.Priority)
+	ret += fmt.Sprintf("Type: %d, ", s.Type)
+	ret += fmt.Sprintf("Table: %d", s.Table)
+
+	return ret
+}
+
+// Print all known information about a route in human readable form
+func (s *FIBPath) Print() string {
+	ret := fmt.Sprintf("\t\tSource: %s\n", s.Src.String())
+	ret += fmt.Sprintf("\t\tNextHop: %s\n", s.NextHop.String())
+	ret += fmt.Sprintf("\t\tPriority: %d\n", s.Priority)
+	ret += fmt.Sprintf("\t\tType: %d\n", s.Type)
+	ret += fmt.Sprintf("\t\tTable: %d\n", s.Table)
+
+	return ret
+}
diff --git a/route/netlink_path.go b/route/netlink_path.go
deleted file mode 100644
index cb374fe8c7672d417641b07c22187620feabea58..0000000000000000000000000000000000000000
--- a/route/netlink_path.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package route
-
-import (
-	"fmt"
-
-	bnet "github.com/bio-routing/bio-rd/net"
-	"github.com/vishvananda/netlink"
-)
-
-const (
-	ProtoUnspec   = 0  // unspec (from /etc/iproute2/rt_protos)
-	ProtoRedirect = 1  // redirect (from /etc/iproute2/rt_protos)
-	ProtoKernel   = 2  // kernel (from /etc/iproute2/rt_protos)
-	ProtoBoot     = 3  // boot (from /etc/iproute2/rt_protos)
-	ProtoStatic   = 4  // static (from /etc/iproute2/rt_protos)
-	ProtoZebra    = 11 // zebra (from /etc/iproute2/rt_protos)
-	ProtoBird     = 12 // bird (from /etc/iproute2/rt_protos)
-	ProtoDHCP     = 16 // dhcp (from /etc/iproute2/rt_protos)
-	ProtoBio      = 45 // bio
-)
-
-// NetlinkPath represents a path learned via Netlink of a route
-type NetlinkPath struct {
-	Src      bnet.IP
-	NextHop  bnet.IP // GW
-	Priority int
-	Protocol int
-	Type     int
-	Table    int
-	Kernel   bool // True if the route is already installed in the kernel
-}
-
-// NewNlPathFromBgpPath creates a new NetlinkPath object from a BGPPath object
-func NewNlPathFromBgpPath(p *BGPPath) *NetlinkPath {
-	return &NetlinkPath{
-		Src:      p.Source,
-		NextHop:  p.NextHop,
-		Protocol: ProtoBio,
-		Kernel:   false,
-	}
-}
-
-// NewNlPathFromRoute creates a new NetlinkPath object from a netlink.Route object
-func NewPathsFromNlRoute(r netlink.Route, kernel bool) (bnet.Prefix, []*Path, error) {
-	var src bnet.IP
-	var dst bnet.Prefix
-
-	if r.Src == nil && r.Dst == nil {
-		return bnet.Prefix{}, nil, fmt.Errorf("Cannot create NlPath, since source and destination are both nil")
-	}
-
-	if r.Src == nil && r.Dst != nil {
-		dst = bnet.NewPfxFromIPNet(r.Dst)
-		if dst.Addr().IsIPv4() {
-			src = bnet.IPv4(0)
-		} else {
-			src = bnet.IPv6(0, 0)
-		}
-	}
-
-	if r.Src != nil && r.Dst == nil {
-		src, _ = bnet.IPFromBytes(r.Src)
-		if src.IsIPv4() {
-			dst = bnet.NewPfx(bnet.IPv4(0), 0)
-		} else {
-			dst = bnet.NewPfx(bnet.IPv6(0, 0), 0)
-		}
-	}
-
-	if r.Src != nil && r.Dst != nil {
-		src, _ = bnet.IPFromBytes(r.Src)
-		dst = bnet.NewPfxFromIPNet(r.Dst)
-	}
-
-	paths := make([]*Path, 0)
-
-	if len(r.MultiPath) > 0 {
-		for _, multiPath := range r.MultiPath {
-			nextHop, _ := bnet.IPFromBytes(multiPath.Gw)
-			paths = append(paths, &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
-					Src:      src,
-					NextHop:  nextHop,
-					Priority: r.Priority,
-					Protocol: r.Protocol,
-					Type:     r.Type,
-					Table:    r.Table,
-					Kernel:   kernel,
-				},
-			})
-		}
-	} else {
-		nextHop, _ := bnet.IPFromBytes(r.Gw)
-		paths = append(paths, &Path{
-			Type: NetlinkPathType,
-			NetlinkPath: &NetlinkPath{
-				Src:      src,
-				NextHop:  nextHop,
-				Priority: r.Priority,
-				Protocol: r.Protocol,
-				Type:     r.Type,
-				Table:    r.Table,
-				Kernel:   kernel,
-			},
-		})
-	}
-
-	return dst, paths, nil
-}
-
-// Select compares s with t and returns negative if s < t, 0 if paths are equal, positive if s > t
-func (s *NetlinkPath) Select(t *NetlinkPath) int8 {
-	if s.NextHop.Compare(t.NextHop) < 0 {
-		return -1
-	}
-
-	if s.NextHop.Compare(t.NextHop) > 0 {
-		return 1
-	}
-
-	if s.Src.Compare(t.Src) < 0 {
-		return -1
-	}
-
-	if s.Src.Compare(t.Src) > 0 {
-		return 1
-	}
-
-	if s.Priority < t.Priority {
-		return -1
-	}
-
-	if s.Priority > t.Priority {
-		return 1
-	}
-
-	if s.Protocol < t.Protocol {
-		return -1
-	}
-
-	if s.Protocol > t.Protocol {
-		return 1
-	}
-
-	if s.Table < t.Table {
-		return -1
-	}
-
-	if s.Table > t.Table {
-		return 1
-	}
-
-	return 0
-}
-
-// ECMP determines if path s and t are equal in terms of ECMP
-func (s *NetlinkPath) ECMP(t *NetlinkPath) bool {
-	return s.Src == t.Src && s.Priority == t.Priority && s.Protocol == t.Protocol && s.Type == t.Type && s.Table == t.Table
-}
-
-// Copy duplicates the current object
-func (s *NetlinkPath) Copy() *NetlinkPath {
-	if s == nil {
-		return nil
-	}
-
-	cp := *s
-	return &cp
-}
-
-// Print all known information about a route in logfile friendly format
-func (s *NetlinkPath) String() string {
-	ret := fmt.Sprintf("Source: %s, ", s.Src.String())
-	ret += fmt.Sprintf("NextHop: %s, ", s.NextHop.String())
-	ret += fmt.Sprintf("Priority: %d, ", s.Priority)
-	ret += fmt.Sprintf("Type: %d, ", s.Type)
-	ret += fmt.Sprintf("Table: %d", s.Table)
-
-	return ret
-}
-
-// Print all known information about a route in human readable form
-func (s *NetlinkPath) Print() string {
-	ret := fmt.Sprintf("\t\tSource: %s\n", s.Src.String())
-	ret += fmt.Sprintf("\t\tNextHop: %s\n", s.NextHop.String())
-	ret += fmt.Sprintf("\t\tPriority: %d\n", s.Priority)
-	ret += fmt.Sprintf("\t\tType: %d\n", s.Type)
-	ret += fmt.Sprintf("\t\tTable: %d\n", s.Table)
-
-	return ret
-}
diff --git a/route/path.go b/route/path.go
index 0d1a64f47a894a8e70fbcd2172877e5dbee19c26..3fa6155f9b6af1b076e44debe1309f79eedd0184 100644
--- a/route/path.go
+++ b/route/path.go
@@ -8,10 +8,10 @@ import (
 
 // Path represents a network path
 type Path struct {
-	Type        uint8
-	StaticPath  *StaticPath
-	BGPPath     *BGPPath
-	NetlinkPath *NetlinkPath
+	Type       uint8
+	StaticPath *StaticPath
+	BGPPath    *BGPPath
+	FIBPath    *FIBPath
 }
 
 // Select returns negative if p < q, 0 if paths are equal, positive if p > q
@@ -39,8 +39,8 @@ func (p *Path) Select(q *Path) int8 {
 		return p.BGPPath.Select(q.BGPPath)
 	case StaticPathType:
 		return p.StaticPath.Select(q.StaticPath)
-	case NetlinkPathType:
-		return p.NetlinkPath.Select(q.NetlinkPath)
+	case FIBPathType:
+		return p.FIBPath.Select(q.FIBPath)
 	}
 
 	panic("Unknown path type")
@@ -53,8 +53,8 @@ func (p *Path) ECMP(q *Path) bool {
 		return p.BGPPath.ECMP(q.BGPPath)
 	case StaticPathType:
 		return p.StaticPath.ECMP(q.StaticPath)
-	case NetlinkPathType:
-		return p.NetlinkPath.ECMP(q.NetlinkPath)
+	case FIBPathType:
+		return p.FIBPath.ECMP(q.FIBPath)
 	}
 
 	panic("Unknown path type")
@@ -110,8 +110,8 @@ func (p *Path) String() string {
 		return "not implemented yet"
 	case BGPPathType:
 		return p.BGPPath.String()
-	case NetlinkPathType:
-		return p.NetlinkPath.String()
+	case FIBPathType:
+		return p.FIBPath.String()
 	default:
 		return "Unknown paty type. Probably not implemented yet"
 	}
@@ -125,7 +125,7 @@ func (p *Path) Print() string {
 		protocol = "static"
 	case BGPPathType:
 		protocol = "BGP"
-	case NetlinkPathType:
+	case FIBPathType:
 		protocol = "Netlink"
 	}
 
@@ -135,8 +135,8 @@ func (p *Path) Print() string {
 		ret += "Not implemented yet"
 	case BGPPathType:
 		ret += p.BGPPath.Print()
-	case NetlinkPathType:
-		ret += p.NetlinkPath.Print()
+	case FIBPathType:
+		ret += p.FIBPath.Print()
 	}
 
 	return ret
@@ -162,8 +162,8 @@ func (p *Path) NextHop() bnet.IP {
 		return p.BGPPath.NextHop
 	case StaticPathType:
 		return p.StaticPath.NextHop
-	case NetlinkPathType:
-		return p.NetlinkPath.NextHop
+	case FIBPathType:
+		return p.FIBPath.NextHop
 	}
 
 	panic("Unknown path type")
diff --git a/route/path_test.go b/route/path_test.go
index 84b3cde044750bcc75eb44ac89ff894c619d5cf3..42961958d75f4ed34cd6a56023fb9652d9b9ebcb 100644
--- a/route/path_test.go
+++ b/route/path_test.go
@@ -6,7 +6,6 @@ import (
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/stretchr/testify/assert"
-	"github.com/vishvananda/netlink"
 )
 
 func TestPathNextHop(t *testing.T) {
@@ -38,8 +37,8 @@ func TestPathNextHop(t *testing.T) {
 		{
 			name: "Netlink Path",
 			p: &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
+				Type: FIBPathType,
+				FIBPath: &FIBPath{
 					NextHop: bnet.IPv4(1000),
 				},
 			},
@@ -151,12 +150,12 @@ func TestSelect(t *testing.T) {
 		{
 			name: "Netlink",
 			p: &Path{
-				Type:        NetlinkPathType,
-				NetlinkPath: &NetlinkPath{},
+				Type:    FIBPathType,
+				FIBPath: &FIBPath{},
 			},
 			q: &Path{
-				Type:        NetlinkPathType,
-				NetlinkPath: &NetlinkPath{},
+				Type:    FIBPathType,
+				FIBPath: &FIBPath{},
 			},
 			expected: 0,
 		},
@@ -328,7 +327,7 @@ func TestNewNlPath(t *testing.T) {
 	tests := []struct {
 		name     string
 		source   *Path
-		expected *NetlinkPath
+		expected *FIBPath
 	}{
 		{
 			name: "BGPPath",
@@ -338,7 +337,7 @@ func TestNewNlPath(t *testing.T) {
 					NextHop: bnet.IPv4(123),
 				},
 			},
-			expected: &NetlinkPath{
+			expected: &FIBPath{
 				NextHop:  bnet.IPv4(123),
 				Protocol: ProtoBio,
 			},
@@ -346,7 +345,7 @@ func TestNewNlPath(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		var converted *NetlinkPath
+		var converted *FIBPath
 
 		switch test.source.Type {
 		case BGPPathType:
@@ -360,245 +359,6 @@ func TestNewNlPath(t *testing.T) {
 	}
 }
 
-func TestNewPathsFromNetlinkRoute(t *testing.T) {
-	tests := []struct {
-		name          string
-		source        netlink.Route
-		expectedPfx   bnet.Prefix
-		expectedPaths []*Path
-		expectError   bool
-	}{
-		{
-			name: "Simple",
-			source: netlink.Route{
-				Dst:      bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
-				Src:      bnet.IPv4(456).Bytes(),
-				Gw:       bnet.IPv4(789).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv4(456),
-						NextHop:  bnet.IPv4(789),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "Multiple nexthop",
-			source: netlink.Route{
-				Dst: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
-				Src: bnet.IPv4(456).Bytes(),
-				MultiPath: []*netlink.NexthopInfo{
-					{
-						LinkIndex: 1,
-						Hops:      1,
-						Gw:        bnet.IPv4(123).Bytes(),
-						Flags:     0,
-						NewDst:    nil,
-						Encap:     nil,
-					}, {
-						LinkIndex: 2,
-						Hops:      1,
-						Gw:        bnet.IPv4(345).Bytes(),
-						Flags:     0,
-						NewDst:    nil,
-						Encap:     nil,
-					},
-				},
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv4(456),
-						NextHop:  bnet.IPv4(123),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				}, {
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv4(456),
-						NextHop:  bnet.IPv4(345),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "No source but destination",
-			source: netlink.Route{
-				Dst:      bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8).GetIPNet(),
-				Gw:       bnet.IPv4(789).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(10, 0, 0, 0), 8),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv4(0),
-						NextHop:  bnet.IPv4(789),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "Source but no destination",
-			source: netlink.Route{
-				Src:      bnet.IPv4(456).Bytes(),
-				Gw:       bnet.IPv4(789).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv4FromOctets(0, 0, 0, 0), 0),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv4(456),
-						NextHop:  bnet.IPv4(789),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "No source but no destination",
-			source: netlink.Route{
-				Gw:       bnet.IPv4(789).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx:   bnet.Prefix{},
-			expectedPaths: []*Path{},
-			expectError:   true,
-		},
-		{
-			name: "No source but destination IPv6",
-			source: netlink.Route{
-				Dst:      bnet.NewPfx(bnet.IPv6(2001, 0), 48).GetIPNet(),
-				Gw:       bnet.IPv6(2001, 123).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv6(2001, 0), 48),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv6(0, 0),
-						NextHop:  bnet.IPv6(2001, 123),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "Source but no destination IPv6",
-			source: netlink.Route{
-				Src:      bnet.IPv6(2001, 456).Bytes(),
-				Gw:       bnet.IPv6(2001, 789).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx: bnet.NewPfx(bnet.IPv6(0, 0), 0),
-			expectedPaths: []*Path{
-				{
-					Type: NetlinkPathType,
-					NetlinkPath: &NetlinkPath{
-						Src:      bnet.IPv6(2001, 456),
-						NextHop:  bnet.IPv6(2001, 789),
-						Protocol: ProtoKernel,
-						Priority: 1,
-						Table:    254,
-						Type:     1,
-						Kernel:   true,
-					},
-				},
-			},
-			expectError: false,
-		},
-		{
-			name: "no source no destination",
-			source: netlink.Route{
-				Gw:       bnet.IPv4(123).Bytes(),
-				Protocol: ProtoKernel,
-				Priority: 1,
-				Table:    254,
-				Type:     1,
-			},
-			expectedPfx:   bnet.NewPfx(bnet.IPv4(0), 0),
-			expectedPaths: []*Path{{}},
-			expectError:   true,
-		},
-	}
-
-	for _, test := range tests {
-		pfx, paths, err := NewPathsFromNlRoute(test.source, true)
-		if test.expectError {
-			assert.Error(t, err)
-		} else {
-			assert.NoError(t, err)
-			assert.Equalf(t, test.expectedPaths, paths, test.name)
-			assert.Equalf(t, test.expectedPfx, pfx, test.name)
-		}
-	}
-}
-
 func TestECMP(t *testing.T) {
 	tests := []struct {
 		name  string
@@ -648,11 +408,12 @@ func TestECMP(t *testing.T) {
 				},
 			},
 			ecmp: false,
-		}, {
+		},
+		{
 			name: "Netlink Path ecmp",
 			left: &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
+				Type: FIBPathType,
+				FIBPath: &FIBPath{
 					Src:      bnet.IPv4(123),
 					Priority: 1,
 					Protocol: 1,
@@ -661,8 +422,8 @@ func TestECMP(t *testing.T) {
 				},
 			},
 			right: &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
+				Type: FIBPathType,
+				FIBPath: &FIBPath{
 					Src:      bnet.IPv4(123),
 					Priority: 1,
 					Protocol: 1,
@@ -674,8 +435,8 @@ func TestECMP(t *testing.T) {
 		}, {
 			name: "Netlink Path not ecmp",
 			left: &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
+				Type: FIBPathType,
+				FIBPath: &FIBPath{
 					Src:      bnet.IPv4(123),
 					Priority: 1,
 					Protocol: 1,
@@ -684,8 +445,8 @@ func TestECMP(t *testing.T) {
 				},
 			},
 			right: &Path{
-				Type: NetlinkPathType,
-				NetlinkPath: &NetlinkPath{
+				Type: FIBPathType,
+				FIBPath: &FIBPath{
 					Src:      bnet.IPv4(123),
 					Priority: 2,
 					Protocol: 1,
@@ -734,23 +495,23 @@ func TestECMP(t *testing.T) {
 	}
 }
 
-func TestNetlinkPathSelect(t *testing.T) {
+func TestFIBPathSelect(t *testing.T) {
 	tests := []struct {
 		name     string
-		left     *NetlinkPath
-		right    *NetlinkPath
+		left     *FIBPath
+		right    *FIBPath
 		expected int8
 	}{
 		{
 			name: "equal",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				NextHop:  bnet.IPv4(123),
 				Src:      bnet.IPv4(234),
 				Priority: 1,
 				Protocol: 1,
 				Table:    1,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				NextHop:  bnet.IPv4(123),
 				Src:      bnet.IPv4(234),
 				Priority: 1,
@@ -761,100 +522,100 @@ func TestNetlinkPathSelect(t *testing.T) {
 		},
 		{
 			name: "nextHop smaller",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				NextHop: bnet.IPv4(1),
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				NextHop: bnet.IPv4(2),
 			},
 			expected: -1,
 		},
 		{
 			name: "nextHop bigger",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				NextHop: bnet.IPv4(2),
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				NextHop: bnet.IPv4(1),
 			},
 			expected: 1,
 		},
 		{
 			name: "src smaller",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Src: bnet.IPv4(1),
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Src: bnet.IPv4(2),
 			},
 			expected: -1,
 		},
 		{
 			name: "src bigger",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Src: bnet.IPv4(2),
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Src: bnet.IPv4(1),
 			},
 			expected: 1,
 		},
 		{
 			name: "priority smaller",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Priority: 1,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Priority: 2,
 			},
 			expected: -1,
 		},
 		{
 			name: "priority bigger",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Priority: 2,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Priority: 1,
 			},
 			expected: 1,
 		},
 		{
 			name: "protocol smaller",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Protocol: 1,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Protocol: 2,
 			},
 			expected: -1,
 		},
 		{
 			name: "protocol bigger",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Protocol: 2,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Protocol: 1,
 			},
 			expected: 1,
 		},
 		{
 			name: "table smaller",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Table: 1,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Table: 2,
 			},
 			expected: -1,
 		},
 		{
 			name: "table bigger",
-			left: &NetlinkPath{
+			left: &FIBPath{
 				Table: 2,
 			},
-			right: &NetlinkPath{
+			right: &FIBPath{
 				Table: 1,
 			},
 			expected: 1,
diff --git a/route/route.go b/route/route.go
index fccb5955303ab04661b80802ce29e896fd2bf9de..1395b157f843559f9e82b51e247cc063faa17e23 100644
--- a/route/route.go
+++ b/route/route.go
@@ -6,7 +6,6 @@ import (
 	"sync"
 
 	"github.com/bio-routing/bio-rd/net"
-	"github.com/vishvananda/netlink"
 )
 
 const (
@@ -24,8 +23,8 @@ const (
 	// ISISPathType indicates a path is an ISIS path
 	ISISPathType
 
-	// NetlinkPathType indicates a path is an Netlink/Kernel path
-	NetlinkPathType
+	// FIBPathType indicates a path is a FIB path
+	FIBPathType
 )
 
 // Route links a prefix to paths
@@ -278,51 +277,3 @@ func (r *Route) Print() string {
 
 	return ret
 }
-
-// NetlinkRouteDiff gets the list of elements contained by a but not b
-func NetlinkRouteDiff(a, b []netlink.Route) []netlink.Route {
-	ret := make([]netlink.Route, 0)
-
-	for _, pa := range a {
-		if !netlinkRoutesContains(pa, b) {
-			ret = append(ret, pa)
-		}
-	}
-
-	return ret
-}
-
-func netlinkRoutesContains(needle netlink.Route, haystack []netlink.Route) bool {
-	for i := range haystack {
-		if netlinkRouteEquals(&needle, &haystack[i]) {
-			return true
-		}
-	}
-
-	return false
-}
-
-func netlinkRouteEquals(a, b *netlink.Route) bool {
-	aMaskSize, aMaskBits := a.Dst.Mask.Size()
-	bMaskSize, bMaskBits := b.Dst.Mask.Size()
-
-	return a.LinkIndex == b.LinkIndex &&
-		a.ILinkIndex == b.ILinkIndex &&
-		a.Scope == b.Scope &&
-
-		a.Dst.IP.Equal(b.Dst.IP) &&
-		aMaskSize == bMaskSize &&
-		aMaskBits == bMaskBits &&
-
-		a.Src.Equal(b.Src) &&
-		a.Gw.Equal(b.Gw) &&
-
-		a.Protocol == b.Protocol &&
-		a.Priority == b.Priority &&
-		a.Table == b.Table &&
-		a.Type == b.Type &&
-		a.Tos == b.Tos &&
-		a.Flags == b.Flags &&
-		a.MTU == b.MTU &&
-		a.AdvMSS == b.AdvMSS
-}
diff --git a/route/route_test.go b/route/route_test.go
index b23a39e1a7ef14b127993ec7b64583f31110c118..bb3162ca1ff2935dbace2a7392fa629904e3cab8 100644
--- a/route/route_test.go
+++ b/route/route_test.go
@@ -1,158 +1,13 @@
 package route
 
 import (
-	"net"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"github.com/vishvananda/netlink"
 
 	bnet "github.com/bio-routing/bio-rd/net"
 )
 
-func TestNetlinkRouteDiff(t *testing.T) {
-	tests := []struct {
-		name     string
-		left     []netlink.Route
-		right    []netlink.Route
-		expected []netlink.Route
-	}{
-		{
-			name: "Equal",
-			left: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-			right: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-			expected: []netlink.Route{},
-		}, {
-			name: "Left empty",
-			left: []netlink.Route{},
-			right: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-			expected: []netlink.Route{},
-		}, {
-			name: "Right empty",
-			left: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-			right: []netlink.Route{},
-			expected: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-		}, {
-			name: "Diff",
-			left: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-			right: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(10, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 1,
-				},
-			},
-			expected: []netlink.Route{
-				{
-					Dst: &net.IPNet{
-						IP:   net.IPv4(20, 0, 0, 1),
-						Mask: net.IPv4Mask(255, 0, 0, 0),
-					},
-					Table: 2,
-				},
-			},
-		},
-	}
-
-	for _, test := range tests {
-		res := NetlinkRouteDiff(test.left, test.right)
-		assert.Equal(t, test.expected, res)
-	}
-
-}
-
 func TestNewRoute(t *testing.T) {
 	tests := []struct {
 		name     string