diff --git a/net/ip.go b/net/ip.go
new file mode 100644
index 0000000000000000000000000000000000000000..efbac355c6edd7eb02654eabc60484452a22316e
--- /dev/null
+++ b/net/ip.go
@@ -0,0 +1,46 @@
+package net
+
+// IP represents an IPv4 or IPv6 address
+type IP struct {
+	higher uint64
+	lower  uint64
+}
+
+func IPv4(val uint32) IP {
+	return IP{
+		lower: uint64(val),
+	}
+}
+
+func IPv6(higher, lower uint64) IP {
+	return IP{
+		higher: higher,
+		lower:  lower,
+	}
+}
+
+// ToUint32 returns the uint32 representation of an IP address
+func (ip *IP) ToUint32() uint32 {
+	return uint32(^uint64(0) >> 32 & ip.lower)
+}
+
+// Compare compares two IP addresses (returns 0 if equal, -1 if `ip` is smaller than `other`, 1 if `ip` is greater than `other`)
+func (ip *IP) Compare(other *IP) int {
+	if ip.higher == other.higher && ip.lower == other.lower {
+		return 0
+	}
+
+	if ip.higher > other.higher {
+		return 1
+	}
+
+	if ip.higher < other.higher {
+		return -1
+	}
+
+	if ip.lower > other.lower {
+		return 1
+	}
+
+	return -1
+}
diff --git a/net/ip_test.go b/net/ip_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..fe199241276439b2a3cc65b8bcb130be92f58ea6
--- /dev/null
+++ b/net/ip_test.go
@@ -0,0 +1,111 @@
+package net
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestToUint32(t *testing.T) {
+	tests := []struct {
+		name     string
+		val      uint64
+		expected uint32
+	}{
+		{
+			name:     "IP: 172.24.5.1",
+			val:      2887255297,
+			expected: 2887255297,
+		},
+		{
+			name:     "bigger than IPv4 address",
+			val:      2887255295 + 17179869184,
+			expected: 2887255295,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			ip := IP{
+				lower: test.val,
+			}
+			assert.Equal(t, test.expected, ip.ToUint32())
+		})
+	}
+}
+
+func TestCompare(t *testing.T) {
+	tests := []struct {
+		name     string
+		ip       *IP
+		other    *IP
+		expected int
+	}{
+		{
+			name: "equal",
+			ip: &IP{
+				lower:  100,
+				higher: 200,
+			},
+			other: &IP{
+				lower:  100,
+				higher: 200,
+			},
+			expected: 0,
+		},
+		{
+			name: "greater higher word",
+			ip: &IP{
+				lower:  123,
+				higher: 200,
+			},
+			other: &IP{
+				lower:  456,
+				higher: 100,
+			},
+			expected: 1,
+		},
+		{
+			name: "lesser higher word",
+			ip: &IP{
+				lower:  123,
+				higher: 100,
+			},
+			other: &IP{
+				lower:  456,
+				higher: 200,
+			},
+			expected: -1,
+		},
+		{
+			name: "equal higher word but lesser lower word",
+			ip: &IP{
+				lower:  456,
+				higher: 100,
+			},
+			other: &IP{
+				lower:  123,
+				higher: 100,
+			},
+			expected: 1,
+		},
+		{
+			name: "equal higher word but lesser lower word",
+			ip: &IP{
+				lower:  123,
+				higher: 100,
+			},
+			other: &IP{
+				lower:  456,
+				higher: 100,
+			},
+			expected: -1,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			assert.Equal(t, test.expected, test.ip.Compare(test.other))
+		})
+	}
+}
diff --git a/route/bgp_path.go b/route/bgp_path.go
index 55db7045e83a50f59ac002ffa8363bbea5db538f..373888abed2644958b4bd3597d4678027287909e 100644
--- a/route/bgp_path.go
+++ b/route/bgp_path.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"strings"
 
+	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -12,7 +13,7 @@ import (
 // BGPPath represents a set of BGP path attributes
 type BGPPath struct {
 	PathIdentifier    uint32
-	NextHop           uint32
+	NextHop           bnet.IP
 	LocalPref         uint32
 	ASPath            packet.ASPath
 	ASPathLen         uint16