diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go
index d59149a9d50360b698edf8d9a2f2066fb8ef11de..71c4236b18f515a2f07d65ebaa829edebb3dcba2 100644
--- a/protocols/bgp/packet/bgp.go
+++ b/protocols/bgp/packet/bgp.go
@@ -1,20 +1,17 @@
 package packet
 
-import (
-	"fmt"
-)
-
 const (
 	OctetLen       = 8
 	MaxASNsSegment = 255
 	BGP4Version    = 4
 	MinOpenLen     = 29
 
-	MarkerLen  = 16
-	HeaderLen  = 19
-	MinLen     = 19
-	MaxLen     = 4096
-	NLRIMaxLen = 5
+	MarkerLen         = 16
+	HeaderLen         = 19
+	MinLen            = 19
+	MaxLen            = 4096
+	NLRIMaxLen        = 5
+	LargeCommunityLen = 12
 
 	OpenMsg         = 1
 	UpdateMsg       = 2
@@ -177,13 +174,3 @@ type Aggretator struct {
 	Addr uint32
 	ASN  uint16
 }
-
-type LargeCommunity struct {
-	GlobalAdministrator uint32
-	DataPart1           uint32
-	DataPart2           uint32
-}
-
-func (c LargeCommunity) String() string {
-	return fmt.Sprintf("(%d,%d,%d)", c.GlobalAdministrator, c.DataPart1, c.DataPart2)
-}
diff --git a/protocols/bgp/packet/large_community.go b/protocols/bgp/packet/large_community.go
new file mode 100644
index 0000000000000000000000000000000000000000..135c86398700e200ba3a4f42e75ca3df33f30ed6
--- /dev/null
+++ b/protocols/bgp/packet/large_community.go
@@ -0,0 +1,46 @@
+package packet
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+type LargeCommunity struct {
+	GlobalAdministrator uint32
+	DataPart1           uint32
+	DataPart2           uint32
+}
+
+func (c LargeCommunity) String() string {
+	return fmt.Sprintf("(%d,%d,%d)", c.GlobalAdministrator, c.DataPart1, c.DataPart2)
+}
+
+func ParseCommunityString(s string) (com LargeCommunity, err error) {
+	s = strings.Trim(s, "()")
+	t := strings.Split(s, ",")
+
+	if len(t) != 3 {
+		return com, fmt.Errorf("can not parse large community %s", s)
+	}
+
+	v, err := strconv.ParseUint(t[0], 10, 32)
+	if err != nil {
+		return com, err
+	}
+	com.GlobalAdministrator = uint32(v)
+
+	v, err = strconv.ParseUint(t[1], 10, 32)
+	if err != nil {
+		return com, err
+	}
+	com.DataPart1 = uint32(v)
+
+	v, err = strconv.ParseUint(t[2], 10, 32)
+	if err != nil {
+		return com, err
+	}
+	com.DataPart2 = uint32(v)
+
+	return com, err
+}
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index 4dc6c49c9d50c94698b44eb953b11d9d5a8a4a39..e20fc48672d20de933b6efa3312382c55ea3f073 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -171,7 +171,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
 func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
 	med, err := pa.decodeUint32(buf)
 	if err != nil {
-		return fmt.Errorf("Unable to recode local pref: %v", err)
+		return fmt.Errorf("Unable to decode local pref: %v", err)
 	}
 
 	pa.Value = uint32(med)
@@ -181,7 +181,7 @@ func (pa *PathAttribute) decodeMED(buf *bytes.Buffer) error {
 func (pa *PathAttribute) decodeLocalPref(buf *bytes.Buffer) error {
 	lpref, err := pa.decodeUint32(buf)
 	if err != nil {
-		return fmt.Errorf("Unable to recode local pref: %v", err)
+		return fmt.Errorf("Unable to decode local pref: %v", err)
 	}
 
 	pa.Value = uint32(lpref)
@@ -216,8 +216,7 @@ func (pa *PathAttribute) decodeAggregator(buf *bytes.Buffer) error {
 
 func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
 	length := pa.Length
-	recordLen := uint16(12)
-	count := length / recordLen
+	count := length / LargeCommunityLen
 
 	coms := make([]LargeCommunity, count)
 
@@ -247,7 +246,7 @@ func (pa *PathAttribute) decodeLargeCommunities(buf *bytes.Buffer) error {
 
 	pa.Value = coms
 
-	dump := pa.Length - (count * recordLen)
+	dump := pa.Length - (count * LargeCommunityLen)
 	return dumpNBytes(buf, dump)
 }
 
@@ -363,6 +362,8 @@ func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 {
 		pathAttrLen = pa.serializeAtomicAggregate(buf)
 	case AggregatorAttr:
 		pathAttrLen = pa.serializeAggregator(buf)
+	case LargeCommunityAttr:
+		pathAttrLen = pa.serializeLargeCommunities(buf)
 	}
 
 	return pathAttrLen
@@ -458,6 +459,32 @@ func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 {
 	return 5
 }
 
+func (pa *PathAttribute) serializeLargeCommunities(buf *bytes.Buffer) uint8 {
+	coms := pa.Value.([]LargeCommunity)
+	if len(coms) == 0 {
+		return 0
+	}
+
+	attrFlags := uint8(0)
+	attrFlags = setOptional(attrFlags)
+	attrFlags = setTransitive(attrFlags)
+	attrFlags = setPartial(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(LargeCommunityAttr)
+
+	length := uint8(LargeCommunityLen * len(coms))
+
+	buf.WriteByte(length)
+
+	for _, com := range coms {
+		buf.Write(convert.Uint32Byte(com.GlobalAdministrator))
+		buf.Write(convert.Uint32Byte(com.DataPart1))
+		buf.Write(convert.Uint32Byte(com.DataPart2))
+	}
+
+	return length
+}
+
 /*func (pa *PathAttribute) PrependASPath(prepend []uint32) {
 	if pa.TypeCode != ASPathAttr {
 		return
@@ -539,6 +566,24 @@ func ParseASPathStr(asPathString string) (*PathAttribute, error) {
 	}, nil
 }
 
+func largeCommunityAttributeForString(s string) (*PathAttribute, error) {
+	strs := strings.Split(s, " ")
+	coms := make([]LargeCommunity, len(strs))
+
+	var err error
+	for i, str := range strs {
+		coms[i], err = ParseCommunityString(str)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &PathAttribute{
+		TypeCode: LargeCommunityAttr,
+		Value:    coms,
+	}, nil
+}
+
 func isBeginOfASSet(asPathPart string) bool {
 	return strings.Contains(asPathPart, "(")
 }
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index 34c62b49e0d569375a1b280e8ef6fc1f3088904a..a56fba0d237d26128af87c500e12a62bb11217b7 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -1195,6 +1195,62 @@ func TestSerializeASPath(t *testing.T) {
 	}
 }
 
+func TestSerializeLargeCommunities(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "2 large communities",
+			input: &PathAttribute{
+				TypeCode: LargeCommunityAttr,
+				Value: []LargeCommunity{
+					{
+						GlobalAdministrator: 1,
+						DataPart1:           2,
+						DataPart2:           3,
+					},
+					{
+						GlobalAdministrator: 4,
+						DataPart1:           5,
+						DataPart2:           6,
+					},
+				},
+			},
+			expected: []byte{
+				0xe0,                                                                   // Attribute flags
+				32,                                                                     // Type
+				24,                                                                     // Length
+				0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, // Communities (1, 2, 3), (4, 5, 6)
+			},
+			expectedLen: 24,
+		},
+		{
+			name: "empty list of communities",
+			input: &PathAttribute{
+				TypeCode: LargeCommunityAttr,
+				Value:    []LargeCommunity{},
+			},
+			expected:    []byte{},
+			expectedLen: 0,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(te *testing.T) {
+			buf := bytes.NewBuffer([]byte{})
+			n := test.input.serializeLargeCommunities(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