From 699ed368e66d3d921b6418921adc4049fbc81644 Mon Sep 17 00:00:00 2001
From: Maximilian Wilhelm <max@sdn.clinic>
Date: Tue, 3 Jul 2018 16:47:03 +0200
Subject: [PATCH] Serialize OriginatorID + ClusterList in update if neighbor is
 a RR client.

Signed-off-by: Maximilian Wilhelm <max@sdn.clinic>
---
 protocols/bgp/packet/path_attributes.go | 55 ++++++++++++++++++++++++-
 protocols/bgp/server/update_sender.go   |  2 +-
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 8544d86b..27ebf806 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -466,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)
 	}
@@ -627,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 {
@@ -696,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,
@@ -743,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/server/update_sender.go b/protocols/bgp/server/update_sender.go
index 146abf0f..8d92ec0b 100644
--- a/protocols/bgp/server/update_sender.go
+++ b/protocols/bgp/server/update_sender.go
@@ -88,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
-- 
GitLab