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