diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 8be484780ee571432d159e63e7b2d4fcf86d2328..748e36535f049ddb31955e8e86078aef209641cd 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -342,6 +342,18 @@ func (pa *PathAttribute) setLength(buf *bytes.Buffer) (int, error) {
 	return bytesRead, nil
 }
 
+func (pa *PathAttribute) Copy() *PathAttribute {
+	return &PathAttribute{
+		ExtendedLength: pa.ExtendedLength,
+		Length:         pa.Length,
+		Optional:       pa.Optional,
+		Partial:        pa.Partial,
+		Transitive:     pa.Transitive,
+		TypeCode:       pa.TypeCode,
+		Value:          pa.Value,
+	}
+}
+
 // dumpNBytes is used to dump n bytes of buf. This is useful in case an path attributes
 // length doesn't match a fixed length's attributes length (e.g. ORIGIN is always an octet)
 func dumpNBytes(buf *bytes.Buffer, n uint16) error {
@@ -378,6 +390,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer, opt *Options) uint8 {
 		pathAttrLen = pa.serializeCommunities(buf)
 	case LargeCommunitiesAttr:
 		pathAttrLen = pa.serializeLargeCommunities(buf)
+	default:
+		pathAttrLen = pa.serializeUnknownAttribute(buf)
 	}
 
 	return pathAttrLen
@@ -534,6 +548,23 @@ func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 {
 	return length
 }
 
+func (pa *PathAttribute) serializeUnknownAttribute(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	if pa.Optional {
+		attrFlags = setOptional(attrFlags)
+	}
+	attrFlags = setTransitive(attrFlags)
+
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(pa.TypeCode)
+
+	b := pa.Value.([]byte)
+	buf.WriteByte(uint8(len(b)))
+	buf.Write(b)
+
+	return uint8(len(b) + 2)
+}
+
 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 96200f4dc8f355da9b640388b097a3a2a9cc5062..fbf1d4806e127b1b2e4b15255a11e018bd00bbaf 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -1345,6 +1345,41 @@ func TestSerializeCommunities(t *testing.T) {
 	}
 }
 
+func TestSerializeUnknownAttribute(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Arbritary attribute",
+			input: &PathAttribute{
+				TypeCode:   200,
+				Value:      []byte{1, 2, 3, 4},
+				Transitive: true,
+			},
+			expected: []byte{
+				64,         // Attribute flags
+				200,        // Type
+				4,          // Length
+				1, 2, 3, 4, // Payload
+			},
+			expectedLen: 6,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			buf := bytes.NewBuffer(nil)
+			n := test.input.serializeUnknownAttribute(buf)
+
+			assert.Equal(t, test.expectedLen, n)
+			assert.Equal(t, test.expected, buf.Bytes())
+		})
+	}
+}
+
 func TestSerialize(t *testing.T) {
 	tests := []struct {
 		name     string
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index e74a660ab859e00b2d70f66175ddc6c750ffd495..fdb6ea30a1463ad06e0cb44507205eed71d7c75b 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -217,32 +217,59 @@ func (s *establishedState) updates(u *packet.BGPUpdate) {
 			Type: route.BGPPathType,
 			BGPPath: &route.BGPPath{
 				Source: bnet.IPv4ToUint32(s.fsm.peer.addr),
+				EBGP:   s.fsm.peer.localASN != s.fsm.peer.peerASN,
 			},
 		}
 
-		for pa := u.PathAttributes; pa != nil; pa = pa.Next {
-			switch pa.TypeCode {
-			case packet.OriginAttr:
-				path.BGPPath.Origin = pa.Value.(uint8)
-			case packet.LocalPrefAttr:
-				path.BGPPath.LocalPref = pa.Value.(uint32)
-			case packet.MEDAttr:
-				path.BGPPath.MED = pa.Value.(uint32)
-			case packet.NextHopAttr:
-				path.BGPPath.NextHop = pa.Value.(uint32)
-			case packet.ASPathAttr:
-				path.BGPPath.ASPath = pa.Value.(packet.ASPath)
-				path.BGPPath.ASPathLen = path.BGPPath.ASPath.Length()
-			case packet.CommunitiesAttr:
-				path.BGPPath.Communities = pa.Value.([]uint32)
-			case packet.LargeCommunitiesAttr:
-				path.BGPPath.LargeCommunities = pa.Value.([]packet.LargeCommunity)
+		s.processAttributes(u.PathAttributes, path)
+
+		s.fsm.adjRIBIn.AddPath(pfx, path)
+	}
+}
+
+func (s *establishedState) processAttributes(attrs *packet.PathAttribute, path *route.Path) {
+	var currentUnknown *packet.PathAttribute
+
+	for pa := attrs; pa != nil; pa = pa.Next {
+		switch pa.TypeCode {
+		case packet.OriginAttr:
+			path.BGPPath.Origin = pa.Value.(uint8)
+		case packet.LocalPrefAttr:
+			path.BGPPath.LocalPref = pa.Value.(uint32)
+		case packet.MEDAttr:
+			path.BGPPath.MED = pa.Value.(uint32)
+		case packet.NextHopAttr:
+			path.BGPPath.NextHop = pa.Value.(uint32)
+		case packet.ASPathAttr:
+			path.BGPPath.ASPath = pa.Value.(packet.ASPath)
+			path.BGPPath.ASPathLen = path.BGPPath.ASPath.Length()
+		case packet.CommunitiesAttr:
+			path.BGPPath.Communities = pa.Value.([]uint32)
+		case packet.LargeCommunitiesAttr:
+			path.BGPPath.LargeCommunities = pa.Value.([]packet.LargeCommunity)
+		default:
+			currentUnknown = s.processUnknownAttribute(pa, currentUnknown)
+			if path.BGPPath.UnknownAttributes == nil {
+				path.BGPPath.UnknownAttributes = currentUnknown
 			}
 		}
-		s.fsm.adjRIBIn.AddPath(pfx, path)
 	}
 }
 
+func (s *establishedState) processUnknownAttribute(attr, current *packet.PathAttribute) *packet.PathAttribute {
+	if !attr.Transitive {
+		return current
+	}
+
+	p := attr.Copy()
+	if current == nil {
+		return p
+	}
+
+	current.Next = p
+	return p
+}
+
 func (s *establishedState) keepaliveReceived() (state, string) {
 	if s.fsm.holdTime != 0 {
 		s.fsm.holdTimer.Reset(s.fsm.holdTime)
diff --git a/protocols/bgp/server/fsm_established_test.go b/protocols/bgp/server/fsm_established_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4e92e4eede30ed4b0dfedeb1217e5d11962c6252
--- /dev/null
+++ b/protocols/bgp/server/fsm_established_test.go
@@ -0,0 +1,65 @@
+package server
+
+import (
+	"testing"
+
+	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/bio-routing/bio-rd/route"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestProcessAttribues(t *testing.T) {
+	unknown3 := &packet.PathAttribute{
+		Transitive: true,
+		TypeCode:   100,
+		Value:      []byte{1, 2, 3, 4},
+		Next:       nil,
+	}
+
+	unknown2 := &packet.PathAttribute{
+		Transitive: false,
+		TypeCode:   150,
+		Value:      []byte{20},
+		Next:       unknown3,
+	}
+
+	unknown1 := &packet.PathAttribute{
+		Transitive: true,
+		TypeCode:   200,
+		Value:      []byte{5, 6},
+		Next:       unknown2,
+	}
+
+	asPath := &packet.PathAttribute{
+		Transitive: true,
+		TypeCode:   packet.ASPathAttr,
+		Value: packet.ASPath{
+			packet.ASPathSegment{
+				Count: 0,
+				Type:  packet.ASSequence,
+				ASNs:  []uint32{},
+			},
+		},
+		Next: unknown1,
+	}
+
+	e := &establishedState{}
+
+	p := &route.Path{
+		BGPPath: &route.BGPPath{},
+	}
+	e.processAttributes(asPath, p)
+
+	expectedCodes := []uint8{200, 100}
+	expectedValues := [][]byte{[]byte{5, 6}, []byte{1, 2, 3, 4}}
+
+	i := 0
+	for attr := p.BGPPath.UnknownAttributes; attr != nil; attr = attr.Next {
+		assert.Equal(t, true, attr.Transitive, "Transitive")
+		assert.Equal(t, expectedCodes[i], attr.TypeCode, "Code")
+		assert.Equal(t, expectedValues[i], attr.Value, "Value")
+		i++
+	}
+
+	assert.Equal(t, i, 2, "Count")
+}
diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go
index 50850cb6e3747f95bee8dd802797269bb3d63724..1fe4fdbaf05d6e483047712861874365a3af74a3 100644
--- a/protocols/bgp/server/update_helper.go
+++ b/protocols/bgp/server/update_helper.go
@@ -34,17 +34,14 @@ func pathAttribues(p *route.Path) (*packet.PathAttribute, error) {
 	nextHop.Next = localPref
 
 	if p.BGPPath != nil {
-		err := addOptionalPathAttribues(p, localPref)
-
-		if err != nil {
-			return nil, err
-		}
+		optionals := addOptionalPathAttribues(p, localPref)
+		optionals.Next = p.BGPPath.UnknownAttributes
 	}
 
 	return asPath, nil
 }
 
-func addOptionalPathAttribues(p *route.Path, parent *packet.PathAttribute) error {
+func addOptionalPathAttribues(p *route.Path, parent *packet.PathAttribute) *packet.PathAttribute {
 	current := parent
 
 	if len(p.BGPPath.Communities) > 0 {
@@ -65,7 +62,7 @@ func addOptionalPathAttribues(p *route.Path, parent *packet.PathAttribute) error
 		current = largeCommunities
 	}
 
-	return nil
+	return current
 }
 
 type serializeAbleUpdate interface {
diff --git a/route/bgp_path.go b/route/bgp_path.go
index d28f586d1cc7059cad7b4c2ead5a3394ff1f2777..175d7bf4c8d45d1a24edc7d6bb0e98b0aafc16d8 100644
--- a/route/bgp_path.go
+++ b/route/bgp_path.go
@@ -11,18 +11,19 @@ import (
 
 // BGPPath represents a set of BGP path attributes
 type BGPPath struct {
-	PathIdentifier   uint32
-	NextHop          uint32
-	LocalPref        uint32
-	ASPath           packet.ASPath
-	ASPathLen        uint16
-	Origin           uint8
-	MED              uint32
-	EBGP             bool
-	BGPIdentifier    uint32
-	Source           uint32
-	Communities      []uint32
-	LargeCommunities []packet.LargeCommunity
+	PathIdentifier    uint32
+	NextHop           uint32
+	LocalPref         uint32
+	ASPath            packet.ASPath
+	ASPathLen         uint16
+	Origin            uint8
+	MED               uint32
+	EBGP              bool
+	BGPIdentifier     uint32
+	Source            uint32
+	Communities       []uint32
+	LargeCommunities  []packet.LargeCommunity
+	UnknownAttributes *packet.PathAttribute
 }
 
 // Legth get's the length of serialized path
@@ -51,6 +52,9 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	// 9.1.2.2.  Breaking Ties (Phase 2)
+
+	// a)
 	if c.ASPathLen > b.ASPathLen {
 		return 1
 	}
@@ -59,6 +63,7 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	// b)
 	if c.Origin > b.Origin {
 		return 1
 	}
@@ -67,6 +72,7 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	// c)
 	if c.MED > b.MED {
 		return 1
 	}
@@ -75,6 +81,18 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	// d)
+	if c.EBGP && !b.EBGP {
+		return -1
+	}
+
+	if !c.EBGP && b.EBGP {
+		return 1
+	}
+
+	// e) TODO: interiour cost (hello IS-IS and OSPF)
+
+	// f)
 	if c.BGPIdentifier < b.BGPIdentifier {
 		return 1
 	}
@@ -83,6 +101,7 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 		return -1
 	}
 
+	// g)
 	if c.Source < b.Source {
 		return 1
 	}
@@ -154,6 +173,7 @@ func (b *BGPPath) better(c *BGPPath) bool {
 	return false
 }
 
+// Print all known information about a route in human readable form
 func (b *BGPPath) Print() string {
 	origin := ""
 	switch b.Origin {
@@ -164,20 +184,29 @@ func (b *BGPPath) Print() string {
 	case 2:
 		origin = "IGP"
 	}
+
+	bgpType := "internal"
+	if b.EBGP {
+		bgpType = "external"
+	}
+
 	ret := fmt.Sprintf("\t\tLocal Pref: %d\n", b.LocalPref)
 	ret += fmt.Sprintf("\t\tOrigin: %s\n", origin)
 	ret += fmt.Sprintf("\t\tAS Path: %v\n", b.ASPath)
+	ret += fmt.Sprintf("\t\tBGP type: %s\n", bgpType)
 	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)
 	ret += fmt.Sprintf("\t\tPath ID: %d\n", b.PathIdentifier)
-	ret += fmt.Sprintf("\t\tSource: %d\n", b.Source)
+	src := uint32To4Byte(b.Source)
+	ret += fmt.Sprintf("\t\tSource: %d.%d.%d.%d\n", src[0], src[1], src[2], src[3])
 	ret += fmt.Sprintf("\t\tCommunities: %v\n", b.Communities)
 	ret += fmt.Sprintf("\t\tLargeCommunities: %v\n", b.LargeCommunities)
 
 	return ret
 }
 
+// Prepend the given BGPPath with the given ASN given times
 func (b *BGPPath) Prepend(asn uint32, times uint16) {
 	if times == 0 {
 		return
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index 180e2aeca7d94d92e078528279ca89ff5a572936..e211479b0480a338259a0dccce1a66b060ebcfe1 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -58,9 +58,6 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 	p = p.Copy()
 	if !a.neighbor.IBGP && !a.neighbor.RouteServerClient {
 		p.BGPPath.Prepend(a.neighbor.LocalASN, 1)
-	}
-
-	if !a.neighbor.IBGP && !a.neighbor.RouteServerClient {
 		p.BGPPath.NextHop = a.neighbor.LocalAddress
 	}
 
@@ -114,14 +111,19 @@ func (a *AdjRIBOut) RemovePath(pfx bnet.Prefix, p *route.Path) bool {
 	}
 
 	a.rt.RemovePath(pfx, p)
-	pathID, err := a.pathIDManager.releasePath(p)
-	if err != nil {
-		log.Warningf("Unable to release path: %v", err)
-		return true
+
+	// If the neighbar has AddPath capabilities, try to find the PathID
+	if a.neighbor.CapAddPathRX {
+		pathID, err := a.pathIDManager.releasePath(p)
+		if err != nil {
+			log.Warningf("Unable to release path for prefix %s: %v", pfx.String(), err)
+			return true
+		}
+
+		p = p.Copy()
+		p.BGPPath.PathIdentifier = pathID
 	}
 
-	p = p.Copy()
-	p.BGPPath.PathIdentifier = pathID
 	a.removePathFromClients(pfx, p)
 	return true
 }