diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index c4d672055c9eb448b9aa08ddc02a7a40a6781d76..a6ee368aa67713d9359732752cfab31e91b22fc0 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -446,6 +446,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 { pathAttrLen = pa.serializeAtomicAggregate(buf) case AggregatorAttr: pathAttrLen = pa.serializeAggregator(buf) + case CommunitiesAttr: + pathAttrLen = pa.serializeCommunities(buf) case LargeCommunityAttr: pathAttrLen = pa.serializeLargeCommunities(buf) } @@ -543,6 +545,30 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 { return 5 } +func (pa *PathAttribute) serializeCommunities(buf *bytes.Buffer) uint8 { + coms := pa.Value.([]uint32) + if len(coms) == 0 { + return 0 + } + + attrFlags := uint8(0) + attrFlags = setOptional(attrFlags) + attrFlags = setTransitive(attrFlags) + attrFlags = setPartial(attrFlags) + buf.WriteByte(attrFlags) + buf.WriteByte(CommunitiesAttr) + + length := uint8(CommunityLen * len(coms)) + + buf.WriteByte(length) + + for _, com := range coms { + buf.Write(convert.Uint32Byte(com)) + } + + return length +} + func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 { coms := pa.Value.([]LargeCommunity) if len(coms) == 0 { diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go index 54cfefd9edef5b619adb1ff93d145b2cea385770..0cc3c3f6861b0616a1b2e054b825626c58187bbc 100644 --- a/protocols/bgp/packet/path_attributes_test.go +++ b/protocols/bgp/packet/path_attributes_test.go @@ -1335,6 +1335,53 @@ func TestSerializeLargeCommunities(t *testing.T) { } } +func TestSerializeCommunities(t *testing.T) { + tests := []struct { + name string + input *PathAttribute + expected []byte + expectedLen uint8 + }{ + { + name: "2 communities", + input: &PathAttribute{ + TypeCode: LargeCommunityAttr, + Value: []uint32{ + 131080, 16778241, + }, + }, + expected: []byte{ + 0xe0, // Attribute flags + 8, // Type + 8, // Length + 0, 2, 0, 8, 1, 0, 4, 1, // Communities (2,8), (256,1025) + }, + expectedLen: 8, + }, + { + name: "empty list of communities", + input: &PathAttribute{ + TypeCode: CommunitiesAttr, + Value: []uint32{}, + }, + expected: []byte{}, + expectedLen: 0, + }, + } + + for _, test := range tests { + t.Run(test.name, func(te *testing.T) { + buf := bytes.NewBuffer([]byte{}) + n := test.input.serializeCommunities(buf) + if n != test.expectedLen { + t.Fatalf("Unexpected length for test %q: %d", test.name, n) + } + + assert.Equal(t, test.expected, buf.Bytes()) + }) + } +} + func TestSerialize(t *testing.T) { tests := []struct { name string