diff --git a/config/peer.go b/config/peer.go
index a192e317d3225560a7076232fac6d217ba4b790c..12124c7c6d3f44928dfaa5a1b9a05fa3bbf645a7 100644
--- a/config/peer.go
+++ b/config/peer.go
@@ -10,20 +10,22 @@ import (
 
 // Peer defines the configuration for a BGP session
 type Peer struct {
-	AdminEnabled      bool
-	ReconnectInterval time.Duration
-	KeepAlive         time.Duration
-	HoldTime          time.Duration
-	LocalAddress      bnet.IP
-	PeerAddress       bnet.IP
-	LocalAS           uint32
-	PeerAS            uint32
-	Passive           bool
-	RouterID          uint32
-	AddPathSend       routingtable.ClientOptions
-	AddPathRecv       bool
-	ImportFilter      *filter.Filter
-	ExportFilter      *filter.Filter
-	RouteServerClient bool
-	IPv6              bool
+	AdminEnabled            bool
+	ReconnectInterval       time.Duration
+	KeepAlive               time.Duration
+	HoldTime                time.Duration
+	LocalAddress            bnet.IP
+	PeerAddress             bnet.IP
+	LocalAS                 uint32
+	PeerAS                  uint32
+	Passive                 bool
+	RouterID                uint32
+	AddPathSend             routingtable.ClientOptions
+	AddPathRecv             bool
+	ImportFilter            *filter.Filter
+	ExportFilter            *filter.Filter
+	RouteServerClient       bool
+	RouteReflectorClient    bool
+	RouteReflectorClusterID uint32
+	IPv6                    bool
 }
diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go
index e008205a2ad95e97872c0a691a479efe42888c24..77b861110faf912a4ddbb0bb3510072b877a659c 100644
--- a/protocols/bgp/packet/bgp.go
+++ b/protocols/bgp/packet/bgp.go
@@ -14,6 +14,7 @@ const (
 	NLRIMaxLen        = 5
 	CommunityLen      = 4
 	LargeCommunityLen = 12
+	ClusterIDLen      = 4
 
 	OpenMsg         = 1
 	UpdateMsg       = 2
@@ -66,6 +67,8 @@ const (
 	AtomicAggrAttr       = 6
 	AggregatorAttr       = 7
 	CommunitiesAttr      = 8
+	OriginatorIDAttr     = 9
+	ClusterListAttr      = 10
 	AS4PathAttr          = 17
 	AS4AggregatorAttr    = 18
 	LargeCommunitiesAttr = 32
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 77025f38ef976917f088509a8481aa3e53a363a5..27ebf80603af0fb91ab4e45adfa1223a0eabe72f 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -99,6 +99,14 @@ func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, c
 		if err := pa.decodeCommunities(buf); err != nil {
 			return nil, consumed, fmt.Errorf("Failed to decode Community: %v", err)
 		}
+	case OriginatorIDAttr:
+		if err := pa.decodeOriginatorID(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+		}
+	case ClusterListAttr:
+		if err := pa.decodeClusterList(buf); err != nil {
+			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+		}
 	case MultiProtocolReachNLRICode:
 		if err := pa.decodeMultiProtocolReachNLRI(buf); err != nil {
 			return nil, consumed, fmt.Errorf("Failed to multi protocol reachable NLRI: %v", err)
@@ -364,6 +372,30 @@ func (pa *PathAttribute) decodeUint32(buf *bytes.Buffer, attrName string) error
 	return nil
 }
 
+func (pa *PathAttribute) decodeOriginatorID(buf *bytes.Buffer) error {
+	return pa.decodeUint32(buf, "OriginatorID")
+}
+
+func (pa *PathAttribute) decodeClusterList(buf *bytes.Buffer) error {
+	if pa.Length%ClusterIDLen != 0 {
+		return fmt.Errorf("Unable to read ClusterList path attribute. Length %d is not divisible by %d", pa.Length, ClusterIDLen)
+	}
+
+	count := pa.Length / ClusterIDLen
+	cids := make([]uint32, count)
+
+	for i := uint16(0); i < count; i++ {
+		v, err := read4BytesAsUint32(buf)
+		if err != nil {
+			return err
+		}
+		cids[i] = v
+	}
+
+	pa.Value = cids
+	return nil
+}
+
 func (pa *PathAttribute) setLength(buf *bytes.Buffer) (int, error) {
 	bytesRead := 0
 	if pa.ExtendedLength {
@@ -434,6 +466,10 @@ func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *types.Options) uint16
 		pathAttrLen = uint16(pa.serializeCommunities(buf))
 	case LargeCommunitiesAttr:
 		pathAttrLen = uint16(pa.serializeLargeCommunities(buf))
+	case OriginatorIDAttr:
+		pathAttrLen = uint16(pa.serializeOriginatorID(buf))
+	case ClusterListAttr:
+		pathAttrLen = uint16(pa.serializeClusterList(buf))
 	default:
 		pathAttrLen = pa.serializeUnknownAttribute(buf)
 	}
@@ -595,6 +631,39 @@ func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 {
 	return length
 }
 
+func (pa *PathAttribute) serializeOriginatorID(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setOptional(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(OriginatorIDAttr)
+	length := uint8(4)
+	buf.WriteByte(length)
+	oid := pa.Value.(uint32)
+	buf.Write(convert.Uint32Byte(oid))
+	return 7
+}
+
+func (pa *PathAttribute) serializeClusterList(buf *bytes.Buffer) uint8 {
+	cids := pa.Value.([]uint32)
+	if len(cids) == 0 {
+		return 0
+	}
+
+	attrFlags := uint8(0)
+	attrFlags = setOptional(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(ClusterListAttr)
+
+	length := uint8(ClusterIDLen * len(cids))
+	buf.WriteByte(length)
+
+	for _, cid := range cids {
+		buf.Write(convert.Uint32Byte(cid))
+	}
+
+	return length
+}
+
 func (pa *PathAttribute) serializeUnknownAttribute(buf *bytes.Buffer) uint16 {
 	attrFlags := uint8(0)
 	if pa.Optional {
@@ -664,7 +733,7 @@ func (pa *PathAttribute) AddOptionalPathAttributes(p *route.Path) *PathAttribute
 }
 
 // PathAttributes converts a path object into a linked list of path attributes
-func PathAttributes(p *route.Path, iBGP bool) (*PathAttribute, error) {
+func PathAttributes(p *route.Path, iBGP bool, rrClient bool) (*PathAttribute, error) {
 	asPath := &PathAttribute{
 		TypeCode: ASPathAttr,
 		Value:    p.BGPPath.ASPath,
@@ -711,6 +780,22 @@ func PathAttributes(p *route.Path, iBGP bool) (*PathAttribute, error) {
 		last = localPref
 	}
 
+	if rrClient {
+		originatorID := &PathAttribute{
+			TypeCode: OriginatorIDAttr,
+			Value:    p.BGPPath.OriginatorID,
+		}
+		last.Next = originatorID
+		last = originatorID
+
+		clusterList := &PathAttribute{
+			TypeCode: ClusterListAttr,
+			Value:    p.BGPPath.ClusterList,
+		}
+		last.Next = clusterList
+		last = clusterList
+	}
+
 	optionals := last.AddOptionalPathAttributes(p)
 
 	last = optionals
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index 3bd225984559e952a1a151c56834d15876a264ab..dd4b31e8005812f7a8f90c36b139d8ac244e320e 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -172,6 +172,80 @@ func TestDecodePathAttr(t *testing.T) {
 			},
 			wantFail: true,
 		},
+		{
+			name: "Missing value OriginatorID",
+			input: []byte{
+				0,
+				OriginatorIDAttr,
+				4,
+			},
+			wantFail: true,
+		},
+		{
+			name: "Valid OriginatorID",
+			input: []byte{
+				128,              // Attr. Flags
+				OriginatorIDAttr, // Attr. Type Code
+				4,                // Attr. Length
+				1, 2, 3, 4,
+			},
+			wantFail: false,
+			expected: &PathAttribute{
+				Length:         4,
+				Optional:       true,
+				Transitive:     false,
+				Partial:        false,
+				ExtendedLength: false,
+				TypeCode:       OriginatorIDAttr,
+				Value:          bnet.IPv4FromOctets(1, 2, 3, 4).ToUint32(),
+			},
+		},
+		{
+			name: "one valid ClusterID",
+			input: []byte{
+				128,             // Attr. Flags
+				ClusterListAttr, // Attr. Type Code
+				4,               // Attr. Length
+				1, 1, 1, 1,
+			},
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ClusterListAttr,
+				Optional: true,
+				Length:   4,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
+				},
+			},
+		},
+		{
+			name: "two valid ClusterIDs",
+			input: []byte{
+				setOptional(uint8(0)),  // Attr. Flags
+				ClusterListAttr,        // Attr. Type Code
+				8,                      // Attr. Length
+				1, 2, 3, 4, 8, 8, 8, 8, // 1.2.3.4, 8.8.8.8
+			},
+			wantFail: false,
+			expected: &PathAttribute{
+				TypeCode: ClusterListAttr,
+				Optional: true,
+				Length:   8,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 2, 3, 4).ToUint32(), bnet.IPv4FromOctets(8, 8, 8, 8).ToUint32(),
+				},
+			},
+		},
+		{
+			name: "one and a half ClusterID",
+			input: []byte{
+				setOptional(uint8(0)), // Attr. Flags
+				ClusterListAttr,       // Attr. Type Code
+				8,                     // Attr. Length
+				1, 2, 3, 4, 8, 8,      // 1.2.3.4, 8.8.
+			},
+			wantFail: true,
+		},
 	}
 
 	for _, test := range tests {
@@ -746,6 +820,85 @@ func TestDecodeCommunity(t *testing.T) {
 	}
 }
 
+func TestDecodeClusterList(t *testing.T) {
+	tests := []struct {
+		name           string
+		input          []byte
+		wantFail       bool
+		explicitLength uint16
+		expected       *PathAttribute
+	}{
+		{
+			name:     "Empty input",
+			input:    []byte{},
+			wantFail: false,
+			expected: &PathAttribute{
+				Length: 0,
+				Value:  []uint32{},
+			},
+		},
+		{
+			name: "one valid ClusterID",
+			input: []byte{
+				1, 1, 1, 1,
+			},
+			wantFail: false,
+			expected: &PathAttribute{
+				Length: 4,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
+				},
+			},
+		},
+		{
+			name: "two valid ClusterIDs",
+			input: []byte{
+				1, 2, 3, 4, 8, 8, 8, 8, // 1.2.3.4, 8.8.8.8
+			},
+			wantFail: false,
+			expected: &PathAttribute{
+				Length: 8,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 2, 3, 4).ToUint32(), bnet.IPv4FromOctets(8, 8, 8, 8).ToUint32(),
+				},
+			},
+		},
+		{
+			name: "one and a half ClusterID",
+			input: []byte{
+				1, 2, 3, 4, 8, 8, // 1.2.3.4, 8.8.
+			},
+			wantFail: true,
+		},
+	}
+
+	for _, test := range tests {
+		l := uint16(len(test.input))
+		if test.explicitLength != 0 {
+			l = test.explicitLength
+		}
+		pa := &PathAttribute{
+			Length: l,
+		}
+		err := pa.decodeClusterList(bytes.NewBuffer(test.input))
+
+		if test.wantFail {
+			if err != nil {
+				continue
+			}
+			t.Errorf("Expected error did not happen for test %q", test.name)
+			continue
+		}
+
+		if err != nil {
+			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
+			continue
+		}
+
+		assert.Equal(t, test.expected, pa)
+	}
+}
+
 func TestDecodeMultiProtocolReachNLRI(t *testing.T) {
 	tests := []struct {
 		name           string
@@ -1420,7 +1573,7 @@ func TestSerializeLargeCommunities(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		t.Run(test.name, func(te *testing.T) {
+		t.Run(test.name, func(t *testing.T) {
 			buf := bytes.NewBuffer([]byte{})
 			n := test.input.serializeLargeCommunities(buf)
 			if n != test.expectedLen {
@@ -1442,7 +1595,7 @@ func TestSerializeCommunities(t *testing.T) {
 		{
 			name: "2 communities",
 			input: &PathAttribute{
-				TypeCode: LargeCommunitiesAttr,
+				TypeCode: CommunitiesAttr,
 				Value: []uint32{
 					131080, 16778241,
 				},
@@ -1467,7 +1620,7 @@ func TestSerializeCommunities(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		t.Run(test.name, func(te *testing.T) {
+		t.Run(test.name, func(t *testing.T) {
 			buf := bytes.NewBuffer([]byte{})
 			n := test.input.serializeCommunities(buf)
 			if n != test.expectedLen {
@@ -1479,6 +1632,106 @@ func TestSerializeCommunities(t *testing.T) {
 	}
 }
 
+func TestSerializeOriginatorID(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Valid OriginatorID",
+			input: &PathAttribute{
+				TypeCode: OriginatorIDAttr,
+				Value:    bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
+			},
+			expected: []byte{
+				setOptional(uint8(0)), // Attribute flags
+				OriginatorIDAttr,      // Type
+				4,                     // Length
+				1, 1, 1, 1,            // ClusterID (1.1.1.1)
+			},
+			expectedLen: 7,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			buf := bytes.NewBuffer(nil)
+			n := test.input.serializeOriginatorID(buf)
+			if n != test.expectedLen {
+				t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			}
+
+			assert.Equal(t, test.expected, buf.Bytes())
+		})
+	}
+}
+
+func TestSerializeClusterList(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Empty list of CluserIDs",
+			input: &PathAttribute{
+				TypeCode: ClusterListAttr,
+				Value:    []uint32{},
+			},
+			expected:    []byte{},
+			expectedLen: 0,
+		},
+		{
+			name: "One ClusterID",
+			input: &PathAttribute{
+				TypeCode: ClusterListAttr,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
+				},
+			},
+			expected: []byte{
+				setOptional(uint8(0)), // Attribute flags
+				ClusterListAttr,       // Type
+				4,                     // Length
+				1, 1, 1, 1,            // ClusterID (1.1.1.1)
+			},
+			expectedLen: 4,
+		},
+		{
+			name: "Two ClusterIDs",
+			input: &PathAttribute{
+				TypeCode: ClusterListAttr,
+				Value: []uint32{
+					bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
+					bnet.IPv4FromOctets(192, 168, 23, 42).ToUint32(),
+				},
+			},
+			expected: []byte{
+				setOptional(uint8(0)),        // Attribute flags
+				ClusterListAttr,              // Type
+				8,                            // Length
+				1, 1, 1, 1, 192, 168, 23, 42, // ClusterID (1.1.1.1)
+			},
+			expectedLen: 8,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			buf := bytes.NewBuffer([]byte{})
+			n := test.input.serializeClusterList(buf)
+			if n != test.expectedLen {
+				t.Fatalf("Unexpected length for test %q: %d", test.name, n)
+			}
+
+			assert.Equal(t, test.expected, buf.Bytes())
+		})
+	}
+}
+
 func TestSerializeUnknownAttribute(t *testing.T) {
 	tests := []struct {
 		name        string
@@ -1724,6 +1977,46 @@ func TestSerialize(t *testing.T) {
 				22, 185, 65, 240, // 185.65.240.0/22
 			},
 		},
+		{
+			name: "Reflected NLRI",
+			msg: &BGPUpdate{
+				NLRI: &NLRI{
+					IP:     strAddr("100.110.128.0"),
+					Pfxlen: 17,
+				},
+				PathAttributes: &PathAttribute{
+					TypeCode: OriginatorIDAttr,
+					Value:    bnet.IPv4FromOctets(9, 8, 7, 6).ToUint32(),
+					Next: &PathAttribute{
+						TypeCode: ClusterListAttr,
+						Value: []uint32{
+							bnet.IPv4FromOctets(1, 2, 3, 4).ToUint32(),
+						},
+					},
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 41, // Length
+				2,    // Msg Type
+				0, 0, // Withdrawn Routes Length
+
+				0, 14, // Total Path Attribute Length
+				// OriginatorID
+				128,        // Attr. Flags (Opt.)
+				9,          // Attr. Type Code
+				4,          // Attr Length
+				9, 8, 7, 6, // 9.8.7.6
+
+				// ClusterList
+				128, // Attr Flags (Opt.)
+				10,  // Attr. Type Code
+				4,
+				1, 2, 3, 4,
+
+				17, 100, 110, 128, // NLRI
+			},
+		},
 	}
 
 	for _, test := range tests {
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index 3c5d96055663e167fc3e451ce03bed2340c757b7..644dde8f1e633465dbb73b4c9decf69a8fc7835a 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -59,7 +59,7 @@ func (s establishedState) run() (state, string) {
 func (s *establishedState) init() error {
 	contributingASNs := s.fsm.rib.GetContributingASNs()
 
-	s.fsm.adjRIBIn = adjRIBIn.New(s.fsm.peer.importFilter, contributingASNs)
+	s.fsm.adjRIBIn = adjRIBIn.New(s.fsm.peer.importFilter, contributingASNs, s.fsm.peer.routerID, s.fsm.peer.clusterID)
 	contributingASNs.Add(s.fsm.peer.localASN)
 	s.fsm.adjRIBIn.Register(s.fsm.rib)
 
@@ -77,13 +77,15 @@ func (s *establishedState) init() error {
 	}
 
 	n := &routingtable.Neighbor{
-		Type:              route.BGPPathType,
-		Address:           s.fsm.peer.addr,
-		IBGP:              s.fsm.peer.localASN == s.fsm.peer.peerASN,
-		LocalASN:          s.fsm.peer.localASN,
-		RouteServerClient: s.fsm.peer.routeServerClient,
-		LocalAddress:      localAddr,
-		CapAddPathRX:      s.fsm.options.AddPathRX,
+		Type:                 route.BGPPathType,
+		Address:              s.fsm.peer.addr,
+		IBGP:                 s.fsm.peer.localASN == s.fsm.peer.peerASN,
+		LocalASN:             s.fsm.peer.localASN,
+		RouteServerClient:    s.fsm.peer.routeServerClient,
+		LocalAddress:         localAddr,
+		CapAddPathRX:         s.fsm.options.AddPathRX,
+		RouteReflectorClient: s.fsm.peer.routeReflectorClient,
+		ClusterID:            s.fsm.peer.clusterID,
 	}
 
 	s.fsm.adjRIBOut = adjRIBOut.New(n, s.fsm.peer.exportFilter)
@@ -291,6 +293,10 @@ func (s *establishedState) processAttributes(attrs *packet.PathAttribute, path *
 			path.BGPPath.Communities = pa.Value.([]uint32)
 		case packet.LargeCommunitiesAttr:
 			path.BGPPath.LargeCommunities = pa.Value.([]types.LargeCommunity)
+		case packet.OriginatorIDAttr:
+			path.BGPPath.OriginatorID = pa.Value.(uint32)
+		case packet.ClusterListAttr:
+			path.BGPPath.ClusterList = pa.Value.([]uint32)
 		default:
 			unknownAttr := s.processUnknownAttribute(pa)
 			if unknownAttr != nil {
diff --git a/protocols/bgp/server/fsm_test.go b/protocols/bgp/server/fsm_test.go
index 2af938822e25b265831033c1b74fd690eef4e90d..5cca8d85ead35eeca7d49d04ab64e0cf8d6dc7ec 100644
--- a/protocols/bgp/server/fsm_test.go
+++ b/protocols/bgp/server/fsm_test.go
@@ -20,6 +20,7 @@ func TestFSM100Updates(t *testing.T) {
 		rib:          locRIB.New(),
 		importFilter: filter.NewAcceptAllFilter(),
 		exportFilter: filter.NewAcceptAllFilter(),
+		routerID:     bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(),
 	})
 
 	fsmA.holdTimer = time.NewTimer(time.Second * 90)
diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go
index 638d8b0314c9b06fa8c65c7bcee24a117ee69388..02cf053bf000c5d1dd232c2243b7b617062a8fcf 100644
--- a/protocols/bgp/server/peer.go
+++ b/protocols/bgp/server/peer.go
@@ -28,17 +28,19 @@ type peer struct {
 	fsms   []*FSM
 	fsmsMu sync.Mutex
 
-	rib               *locRIB.LocRIB
-	routerID          uint32
-	addPathSend       routingtable.ClientOptions
-	addPathRecv       bool
-	reconnectInterval time.Duration
-	keepaliveTime     time.Duration
-	holdTime          time.Duration
-	optOpenParams     []packet.OptParam
-	importFilter      *filter.Filter
-	exportFilter      *filter.Filter
-	routeServerClient bool
+	rib                  *locRIB.LocRIB
+	routerID             uint32
+	addPathSend          routingtable.ClientOptions
+	addPathRecv          bool
+	reconnectInterval    time.Duration
+	keepaliveTime        time.Duration
+	holdTime             time.Duration
+	optOpenParams        []packet.OptParam
+	importFilter         *filter.Filter
+	exportFilter         *filter.Filter
+	routeServerClient    bool
+	routeReflectorClient bool
+	clusterID            uint32
 }
 
 func (p *peer) snapshot() PeerInfo {
@@ -106,22 +108,30 @@ func newPeer(c config.Peer, rib *locRIB.LocRIB, server *bgpServer) (*peer, error
 		c.LocalAS = server.localASN
 	}
 	p := &peer{
-		server:            server,
-		addr:              c.PeerAddress,
-		peerASN:           c.PeerAS,
-		localASN:          c.LocalAS,
-		fsms:              make([]*FSM, 0),
-		rib:               rib,
-		addPathSend:       c.AddPathSend,
-		addPathRecv:       c.AddPathRecv,
-		reconnectInterval: c.ReconnectInterval,
-		keepaliveTime:     c.KeepAlive,
-		holdTime:          c.HoldTime,
-		optOpenParams:     make([]packet.OptParam, 0),
-		importFilter:      filterOrDefault(c.ImportFilter),
-		exportFilter:      filterOrDefault(c.ExportFilter),
-		routeServerClient: c.RouteServerClient,
+		server:               server,
+		addr:                 c.PeerAddress,
+		peerASN:              c.PeerAS,
+		localASN:             c.LocalAS,
+		fsms:                 make([]*FSM, 0),
+		rib:                  rib,
+		addPathSend:          c.AddPathSend,
+		addPathRecv:          c.AddPathRecv,
+		reconnectInterval:    c.ReconnectInterval,
+		keepaliveTime:        c.KeepAlive,
+		holdTime:             c.HoldTime,
+		optOpenParams:        make([]packet.OptParam, 0),
+		importFilter:         filterOrDefault(c.ImportFilter),
+		exportFilter:         filterOrDefault(c.ExportFilter),
+		routeServerClient:    c.RouteServerClient,
+		routeReflectorClient: c.RouteReflectorClient,
+		clusterID:            c.RouteReflectorClusterID,
 	}
+
+	// If we are a route reflector and no ClusterID was set, use our RouterID
+	if p.routeReflectorClient && p.clusterID == 0 {
+		p.clusterID = c.RouterID
+	}
+
 	p.fsms = append(p.fsms, NewActiveFSM2(p))
 
 	caps := make(packet.Capabilities, 0)
diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go
index a223ee1752b63775a32a4715bbbb3232575a86ab..8d92ec0b683cf7b374366c6366bd4aeeefbee2ea 100644
--- a/protocols/bgp/server/update_sender.go
+++ b/protocols/bgp/server/update_sender.go
@@ -17,6 +17,7 @@ type UpdateSender struct {
 	routingtable.ClientManager
 	fsm       *FSM
 	iBGP      bool
+	rrClient  bool
 	toSendMu  sync.Mutex
 	toSend    map[string]*pathPfxs
 	destroyCh chan struct{}
@@ -31,6 +32,7 @@ func newUpdateSender(fsm *FSM) *UpdateSender {
 	return &UpdateSender{
 		fsm:       fsm,
 		iBGP:      fsm.peer.localASN == fsm.peer.peerASN,
+		rrClient:  fsm.peer.routeReflectorClient,
 		destroyCh: make(chan struct{}),
 		toSend:    make(map[string]*pathPfxs),
 	}
@@ -86,7 +88,7 @@ func (u *UpdateSender) sender(aggrTime time.Duration) {
 
 		for key, pathNLRIs := range u.toSend {
 			budget = packet.MaxLen - packet.HeaderLen - packet.MinUpdateLen - int(pathNLRIs.path.BGPPath.Length())
-			pathAttrs, err = packet.PathAttributes(pathNLRIs.path, u.iBGP)
+			pathAttrs, err = packet.PathAttributes(pathNLRIs.path, u.iBGP, u.rrClient)
 			if err != nil {
 				log.Errorf("Unable to get path attributes: %v", err)
 				continue
diff --git a/route/bgp_path.go b/route/bgp_path.go
index ee9aca8343129a52aebf5eac6cd487dc489cb466..a19813aa3158afc27a44a8f794bee600d49ebaf1 100644
--- a/route/bgp_path.go
+++ b/route/bgp_path.go
@@ -27,6 +27,8 @@ type BGPPath struct {
 	Communities       []uint32
 	LargeCommunities  []types.LargeCommunity
 	UnknownAttributes []types.UnknownPathAttribute
+	OriginatorID      uint32
+	ClusterList       []uint32
 }
 
 // Length get's the length of serialized path
@@ -47,12 +49,22 @@ func (b *BGPPath) Length() uint16 {
 		largeCommunitiesLen += 3 + uint16(len(b.LargeCommunities)*12)
 	}
 
+	clusterListLen := uint16(0)
+	if len(b.ClusterList) != 0 {
+		clusterListLen += 3 + uint16(len(b.ClusterList)*4)
+	}
+
 	unknownAttributesLen := uint16(0)
 	for _, unknownAttr := range b.UnknownAttributes {
 		unknownAttributesLen += unknownAttr.WireLength()
 	}
 
-	return communitiesLen + largeCommunitiesLen + 4*7 + 4 + asPathLen + unknownAttributesLen
+	originatorID := uint16(0)
+	if b.OriginatorID != 0 {
+		originatorID = 4
+	}
+
+	return communitiesLen + largeCommunitiesLen + 4*7 + 4 + originatorID + asPathLen + unknownAttributesLen
 }
 
 // ECMP determines if routes b and c are euqal in terms of ECMP
@@ -110,12 +122,33 @@ func (b *BGPPath) Compare(c *BGPPath) int8 {
 
 	// e) TODO: interiour cost (hello IS-IS and OSPF)
 
-	// f)
-	if c.BGPIdentifier < b.BGPIdentifier {
+	// f) + RFC4456 9. (Route Reflection)
+	bgpIdentifierC := c.BGPIdentifier
+	bgpIdentifierB := b.BGPIdentifier
+
+	// IF an OriginatorID (set by an RR) is present, use this instead of Originator
+	if c.OriginatorID != 0 {
+		bgpIdentifierC = c.OriginatorID
+	}
+
+	if b.OriginatorID != 0 {
+		bgpIdentifierB = b.OriginatorID
+	}
+
+	if bgpIdentifierC < bgpIdentifierB {
 		return 1
 	}
 
-	if c.BGPIdentifier > b.BGPIdentifier {
+	if bgpIdentifierC > bgpIdentifierB {
+		return -1
+	}
+
+	// Additionally check for the shorter ClusterList
+	if len(c.ClusterList) < len(b.ClusterList) {
+		return 1
+	}
+
+	if len(c.ClusterList) > len(b.ClusterList) {
 		return -1
 	}
 
@@ -219,6 +252,14 @@ func (b *BGPPath) Print() string {
 	ret += fmt.Sprintf("\t\tCommunities: %v\n", b.Communities)
 	ret += fmt.Sprintf("\t\tLargeCommunities: %v\n", b.LargeCommunities)
 
+	if b.OriginatorID != 0 {
+		oid := uint32To4Byte(b.OriginatorID)
+		ret += fmt.Sprintf("\t\tOriginatorID: %d.%d.%d.%d\n", oid[0], oid[1], oid[2], oid[3])
+	}
+	if b.ClusterList != nil {
+		ret += fmt.Sprintf("\t\tClusterList %s\n", b.ClusterListString())
+	}
+
 	return ret
 }
 
@@ -280,6 +321,11 @@ func (b *BGPPath) Copy() *BGPPath {
 	cp.LargeCommunities = make([]types.LargeCommunity, len(cp.LargeCommunities))
 	copy(cp.LargeCommunities, b.LargeCommunities)
 
+	if b.ClusterList != nil {
+		cp.ClusterList = make([]uint32, len(cp.ClusterList))
+		copy(cp.ClusterList, b.ClusterList)
+	}
+
 	return &cp
 }
 
@@ -295,6 +341,8 @@ func (b *BGPPath) ComputeHash() string {
 		b.BGPIdentifier,
 		b.Source,
 		b.Communities,
+		b.OriginatorID,
+		b.ClusterList,
 		b.LargeCommunities,
 		b.PathIdentifier)
 
@@ -311,6 +359,17 @@ func (b *BGPPath) CommunitiesString() string {
 	return strings.TrimRight(str, " ")
 }
 
+// ClusterListString returns the formated ClusterList
+func (b *BGPPath) ClusterListString() string {
+	str := ""
+	for _, cid := range b.ClusterList {
+		octes := uint32To4Byte(cid)
+		str += fmt.Sprintf("%d.%d.%d.%d ", octes[0], octes[1], octes[2], octes[3])
+	}
+
+	return strings.TrimRight(str, " ")
+}
+
 // LargeCommunitiesString returns the formated communities
 func (b *BGPPath) LargeCommunitiesString() string {
 	str := ""
diff --git a/route/bgp_test.go b/route/bgp_test.go
index f399d5d51ab96ad1a5b789a22aceb4d7b2490932..760306af6c0006479fd2c8c401581b57eff5ab48 100644
--- a/route/bgp_test.go
+++ b/route/bgp_test.go
@@ -36,9 +36,9 @@ func TestComputeHash(t *testing.T) {
 		Source:         bnet.IPv4(4),
 	}
 
-	assert.Equal(t, "98d68e69d993f8807c561cc7d63de759f7edc732887f88a7ebf42f61b9e54821", p.ComputeHash())
+	assert.Equal(t, "1058916ff3e6a51c7d8a47945d13fc3fcd8ee578a6d376505f46d58979b30fae", p.ComputeHash())
 
 	p.LocalPref = 150
 
-	assert.NotEqual(t, "98d68e69d993f8807c561cc7d63de759f7edc732887f88a7ebf42f61b9e54821", p.ComputeHash())
+	assert.NotEqual(t, "1058916ff3e6a51c7d8a47945d13fc3fcd8ee578a6d376505f46d58979b30fae", p.ComputeHash())
 }
diff --git a/routingtable/adjRIBIn/adj_rib_in.go b/routingtable/adjRIBIn/adj_rib_in.go
index bf3bab1c8a4aa14d4f969429e4c10eae0aa74731..319e28690170ae37df83ec2c480cea752b6ce7f1 100644
--- a/routingtable/adjRIBIn/adj_rib_in.go
+++ b/routingtable/adjRIBIn/adj_rib_in.go
@@ -18,14 +18,18 @@ type AdjRIBIn struct {
 	mu               sync.RWMutex
 	exportFilter     *filter.Filter
 	contributingASNs *routingtable.ContributingASNs
+	routerID         uint32
+	clusterID        uint32
 }
 
 // New creates a new Adjacency RIB In
-func New(exportFilter *filter.Filter, contributingASNs *routingtable.ContributingASNs) *AdjRIBIn {
+func New(exportFilter *filter.Filter, contributingASNs *routingtable.ContributingASNs, routerID uint32, clusterID uint32) *AdjRIBIn {
 	a := &AdjRIBIn{
 		rt:               routingtable.NewRoutingTable(),
 		exportFilter:     exportFilter,
 		contributingASNs: contributingASNs,
+		routerID:         routerID,
+		clusterID:        clusterID,
 	}
 	a.ClientManager = routingtable.NewClientManager(a)
 	return a
@@ -64,6 +68,20 @@ func (a *AdjRIBIn) AddPath(pfx net.Prefix, p *route.Path) error {
 	a.mu.Lock()
 	defer a.mu.Unlock()
 
+	// RFC4456 Sect. 8: Ignore route with our RouterID as OriginatorID
+	if p.BGPPath.OriginatorID == a.routerID {
+		return nil
+	}
+
+	// RFC4456 Sect. 8: Ignore routes which contian our ClusterID in their ClusterList
+	if len(p.BGPPath.ClusterList) > 0 {
+		for _, cid := range p.BGPPath.ClusterList {
+			if cid == a.clusterID {
+				return nil
+			}
+		}
+	}
+
 	oldPaths := a.rt.ReplacePath(pfx, p)
 	a.removePathsFromClients(pfx, oldPaths)
 
diff --git a/routingtable/adjRIBIn/adj_rib_in_test.go b/routingtable/adjRIBIn/adj_rib_in_test.go
index 0fb052db2a5e34f26eb2132cf86cd03632f420c7..deec00104931a80f128be6782df70e35407775ae 100644
--- a/routingtable/adjRIBIn/adj_rib_in_test.go
+++ b/routingtable/adjRIBIn/adj_rib_in_test.go
@@ -12,6 +12,9 @@ import (
 )
 
 func TestAddPath(t *testing.T) {
+	routerID := net.IPv4FromOctets(1, 1, 1, 1).ToUint32()
+	clusterID := net.IPv4FromOctets(2, 2, 2, 2).ToUint32()
+
 	tests := []struct {
 		name       string
 		routes     []*route.Route
@@ -72,10 +75,39 @@ func TestAddPath(t *testing.T) {
 				}),
 			},
 		},
+		{
+			name: "Add route with our RouterID as OriginatorID",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 32), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref:    111,
+						OriginatorID: routerID,
+					},
+				}),
+			},
+			expected: []*route.Route{},
+		},
+		{
+			name: "Add route with our ClusterID within ClusterList",
+			routes: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 32), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						LocalPref:    222,
+						OriginatorID: 23,
+						ClusterList: []uint32{
+							clusterID,
+						},
+					},
+				}),
+			},
+			expected: []*route.Route{},
+		},
 	}
 
 	for _, test := range tests {
-		adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs())
+		adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs(), routerID, clusterID)
 		mc := routingtable.NewRTMockClient()
 		adjRIBIn.ClientManager.Register(mc)
 
@@ -83,12 +115,14 @@ func TestAddPath(t *testing.T) {
 			adjRIBIn.AddPath(route.Prefix(), route.Paths()[0])
 		}
 
-		removePathParams := mc.GetRemovePathParams()
-		if removePathParams.Pfx != test.removePfx {
-			t.Errorf("Test %q failed: Call to RemovePath did not propagate prefix properly: Got: %s Want: %s", test.name, removePathParams.Pfx.String(), test.removePfx.String())
-		}
+		if test.removePath != nil {
+			removePathParams := mc.GetRemovePathParams()
+			if removePathParams.Pfx != test.removePfx {
+				t.Errorf("Test %q failed: Call to RemovePath did not propagate prefix properly: Got: %s Want: %s", test.name, removePathParams.Pfx.String(), test.removePfx.String())
+			}
 
-		assert.Equal(t, test.removePath, removePathParams.Path)
+			assert.Equal(t, test.removePath, removePathParams.Path)
+		}
 		assert.Equal(t, test.expected, adjRIBIn.rt.Dump())
 	}
 }
@@ -167,7 +201,7 @@ func TestRemovePath(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs())
+		adjRIBIn := New(filter.NewAcceptAllFilter(), routingtable.NewContributingASNs(), 1, 2)
 		for _, route := range test.routes {
 			adjRIBIn.AddPath(route.Prefix(), route.Paths()[0])
 		}
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index 2685ce37e45bd40fb91f891190a82e2054fee472..b4271ea3c82734d6dd8f5e8dae7f2fb48db34c4b 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -53,8 +53,8 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 		return nil
 	}
 
-	// Don't export routes learned via iBGP to an iBGP neighbor
-	if !p.BGPPath.EBGP && a.neighbor.IBGP {
+	// Don't export routes learned via iBGP to an iBGP neighbor which is NOT a route reflection client
+	if !p.BGPPath.EBGP && a.neighbor.IBGP && !a.neighbor.RouteReflectorClient {
 		return nil
 	}
 
@@ -65,6 +65,27 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 		p.BGPPath.NextHop = a.neighbor.LocalAddress
 	}
 
+	// If the iBGP neighbor is a route reflection client...
+	if a.neighbor.IBGP && a.neighbor.RouteReflectorClient {
+		/*
+		 * RFC4456 Section 8:
+		 * This attribute will carry the BGP Identifier of the originator of the route in the local AS.
+		 * A BGP speaker SHOULD NOT create an ORIGINATOR_ID attribute if one already exists.
+		 */
+		if p.BGPPath.OriginatorID == 0 {
+			p.BGPPath.OriginatorID = p.BGPPath.Source.ToUint32()
+		}
+
+		/*
+		 * When an RR reflects a route, it MUST prepend the local CLUSTER_ID to the CLUSTER_LIST.
+		 * If the CLUSTER_LIST is empty, it MUST create a new one.
+		 */
+		cList := make([]uint32, len(p.BGPPath.ClusterList)+1)
+		copy(cList[1:], p.BGPPath.ClusterList)
+		cList[0] = a.neighbor.ClusterID
+		p.BGPPath.ClusterList = cList
+	}
+
 	p, reject := a.exportFilter.ProcessTerms(pfx, p)
 	if reject {
 		return nil
diff --git a/routingtable/adjRIBOut/adj_rib_out_test.go b/routingtable/adjRIBOut/adj_rib_out_test.go
index 0d01dd0890f06f1c518101205755162b10081c3e..26eceeeed34b37d62303a9156f9074ba28411129 100644
--- a/routingtable/adjRIBOut/adj_rib_out_test.go
+++ b/routingtable/adjRIBOut/adj_rib_out_test.go
@@ -498,7 +498,7 @@ func TestBestPathOnlyIBGP(t *testing.T) {
 			expected: []*route.Route{},
 		},
 		{
-			name: "Try to add route with NO_EXPORT community set (without success)",
+			name: "Try to add route with NO_ADVERTISE community set (without success)",
 			routesAdd: []*route.Route{
 				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
 					Type: route.BGPPathType,
@@ -532,6 +532,337 @@ func TestBestPathOnlyIBGP(t *testing.T) {
 	}
 }
 
+/*
+ * Test for iBGP Route Reflector client neighbor
+ */
+
+func TestBestPathOnlyRRClient(t *testing.T) {
+	neighborBestOnlyRR := &routingtable.Neighbor{
+		Type:                 route.BGPPathType,
+		LocalAddress:         net.IPv4FromOctets(127, 0, 0, 1),
+		Address:              net.IPv4FromOctets(127, 0, 0, 2),
+		IBGP:                 true,
+		LocalASN:             41981,
+		RouteServerClient:    false,
+		CapAddPathRX:         false,
+		RouteReflectorClient: true,
+		ClusterID:            net.IPv4FromOctets(2, 2, 2, 2).ToUint32(),
+	}
+
+	adjRIBOut := New(neighborBestOnlyRR, filter.NewAcceptAllFilter())
+
+	tests := []struct {
+		name          string
+		routesAdd     []*route.Route
+		routesRemove  []*route.Route
+		expected      []*route.Route
+		expectedCount int64
+	}{
+		{
+			name: "Add an iBGP route (with success)",
+			routesAdd: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type:    route.BGPPathType,
+					BGPPath: &route.BGPPath{},
+				}),
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						Communities:      []uint32{},
+						LargeCommunities: []types.LargeCommunity{},
+						ASPath:           types.ASPath{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expectedCount: 1,
+		},
+		{
+			name: "Add an eBGP route (replacing previous iBGP route)",
+			routesAdd: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						EBGP: true,
+						ASPath: types.ASPath{
+							types.ASPathSegment{
+								Type: types.ASSequence,
+								ASNs: []uint32{
+									201701,
+								},
+							},
+						},
+						ASPathLen: 1,
+						NextHop:   net.IPv4FromOctets(1, 2, 3, 4),
+					},
+				}),
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						NextHop: net.IPv4FromOctets(1, 2, 3, 4),
+						ASPath: types.ASPath{
+							types.ASPathSegment{
+								Type: types.ASSequence,
+								ASNs: []uint32{
+									201701,
+								},
+							},
+						},
+						ASPathLen:         1,
+						Origin:            0,
+						MED:               0,
+						EBGP:              true,
+						Communities:       []uint32{},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expectedCount: 1,
+		},
+		{
+			name: "Try to remove slightly different route",
+			routesRemove: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						NextHop: net.IPv4FromOctets(1, 2, 3, 4),
+						ASPath: types.ASPath{
+							types.ASPathSegment{
+								Type: types.ASSequence,
+								ASNs: []uint32{
+									201701,
+								},
+							},
+						},
+						ASPathLen:         1,
+						Origin:            0,
+						MED:               1, // Existing route has MED 0
+						EBGP:              true,
+						Communities:       []uint32{},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{}},
+				}),
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						NextHop: net.IPv4FromOctets(1, 2, 3, 4),
+						ASPath: types.ASPath{
+							types.ASPathSegment{
+								Type: types.ASSequence,
+								ASNs: []uint32{
+									201701,
+								},
+							},
+						},
+						ASPathLen:         1,
+						Origin:            0,
+						MED:               0,
+						EBGP:              true,
+						Communities:       []uint32{},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expectedCount: 1,
+		},
+		{
+			name: "Remove route added in 2nd step",
+			routesRemove: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						NextHop: net.IPv4FromOctets(1, 2, 3, 4),
+						ASPath: types.ASPath{
+							types.ASPathSegment{
+								Type: types.ASSequence,
+								ASNs: []uint32{
+									201701,
+								},
+							},
+						},
+						ASPathLen:         1,
+						Origin:            0,
+						MED:               0,
+						EBGP:              true,
+						Communities:       []uint32{},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expected:      []*route.Route{},
+			expectedCount: 0,
+		},
+		{
+			name: "Try to add route with NO_ADVERTISE community set (without success)",
+			routesAdd: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						Communities: []uint32{
+							types.WellKnownCommunityNoAdvertise,
+						},
+					},
+				}),
+			},
+			expected:      []*route.Route{},
+			expectedCount: 0,
+		},
+		{
+			name: "Try to add route with NO_EXPORT community set (with success)",
+			routesAdd: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						Communities: []uint32{
+							types.WellKnownCommunityNoExport,
+						},
+					},
+				}),
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						ASPath:    types.ASPath{},
+						ASPathLen: 0,
+						Origin:    0,
+						MED:       0,
+						EBGP:      false,
+						Communities: []uint32{
+							types.WellKnownCommunityNoExport,
+						},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expectedCount: 1,
+		},
+		{
+			name: "Remove NO_EXPORT route added before",
+			routesRemove: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						ASPath:    types.ASPath{},
+						ASPathLen: 0,
+						Origin:    0,
+						MED:       0,
+						EBGP:      false,
+						Communities: []uint32{
+							types.WellKnownCommunityNoExport,
+						},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+						},
+					},
+				}),
+			},
+			expected:      []*route.Route{},
+			expectedCount: 0,
+		},
+		{
+			name: "Add route with one entry in ClusterList and OriginatorID set (with success)",
+			routesAdd: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						OriginatorID: 42,
+						ClusterList: []uint32{
+							23,
+						},
+					},
+				}),
+			},
+			expected: []*route.Route{
+				route.NewRoute(net.NewPfx(net.IPv4FromOctets(10, 0, 0, 0), 8), &route.Path{
+					Type: route.BGPPathType,
+					BGPPath: &route.BGPPath{
+						ASPath:            types.ASPath{},
+						ASPathLen:         0,
+						Origin:            0,
+						MED:               0,
+						EBGP:              false,
+						Communities:       []uint32{},
+						LargeCommunities:  []types.LargeCommunity{},
+						UnknownAttributes: nil,
+						PathIdentifier:    0,
+						LocalPref:         0,
+						Source:            net.IP{},
+						ClusterList: []uint32{
+							neighborBestOnlyRR.ClusterID,
+							23,
+						},
+						OriginatorID: 42,
+					},
+				}),
+			},
+			expectedCount: 1,
+		},
+	}
+
+	for i, test := range tests {
+		fmt.Printf("Running RR client best only test #%d: %s\n", i+1, test.name)
+		for _, route := range test.routesAdd {
+			adjRIBOut.AddPath(route.Prefix(), route.Paths()[0])
+		}
+
+		for _, route := range test.routesRemove {
+			adjRIBOut.RemovePath(route.Prefix(), route.Paths()[0])
+		}
+
+		assert.Equal(t, test.expected, adjRIBOut.rt.Dump())
+
+		actualCount := adjRIBOut.RouteCount()
+		if test.expectedCount != actualCount {
+			t.Errorf("Expected route count %d differs from actual route count %d!\n", test.expectedCount, actualCount)
+		}
+	}
+}
+
 /*
  * Test for AddPath capabale peer / AdjRIBOut
  */
diff --git a/routingtable/neighbor.go b/routingtable/neighbor.go
index bf6e97c6af46da590dd071e6e40b9978410f78ce..8b320636806792a2091cdc3cb4556c1b55a842bc 100644
--- a/routingtable/neighbor.go
+++ b/routingtable/neighbor.go
@@ -19,9 +19,15 @@ type Neighbor struct {
 	// Local ASN of session
 	LocalASN uint32
 
-	// Peer is a route server client
+	// RouteServerClient incicates if the peer is a route server client
 	RouteServerClient bool
 
+	// RouteReflectorClient indicates if the peer is a route reflector client
+	RouteReflectorClient bool
+
+	// ClusterID is our route reflectors clusterID
+	ClusterID uint32
+
 	// CapAddPathRX indicates if the peer supports receiving multiple BGP paths
 	CapAddPathRX bool
 }
diff --git a/routingtable/table.go b/routingtable/table.go
index 16317e6fc50b7481c8e259be161b8a9bcba644a3..5fcb911c03f9706903c87ad77c80a010931b726b 100644
--- a/routingtable/table.go
+++ b/routingtable/table.go
@@ -71,13 +71,13 @@ func (rt *RoutingTable) RemovePath(pfx net.Prefix, p *route.Path) {
 	rt.mu.Lock()
 	defer rt.mu.Unlock()
 
-	if rt.removePath(pfx, p) {
-		atomic.AddInt64(&rt.routeCount, -1)
-	}
+	rt.removePath(pfx, p)
 }
 
-func (rt *RoutingTable) removePath(pfx net.Prefix, p *route.Path) bool {
-	return rt.root.removePath(pfx, p)
+func (rt *RoutingTable) removePath(pfx net.Prefix, p *route.Path) {
+	if rt.root.removePath(pfx, p) {
+		atomic.AddInt64(&rt.routeCount, -1)
+	}
 }
 
 func (rt *RoutingTable) removePaths(pfx net.Prefix, paths []*route.Path) {