diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go
index 46be5aed41d781a12696b0811cb2865eb8c91a0c..be4f30dc5890e9abca69a4822a3e7d6187a30a0c 100644
--- a/protocols/bgp/packet/bgp.go
+++ b/protocols/bgp/packet/bgp.go
@@ -4,10 +4,11 @@ const (
 	OctetLen    = 8
 	BGP4Version = 4
 
-	MarkerLen = 16
-	HeaderLen = 19
-	MinLen    = 19
-	MaxLen    = 4096
+	MarkerLen  = 16
+	HeaderLen  = 19
+	MinLen     = 19
+	MaxLen     = 4096
+	NLRIMaxLen = 5
 
 	OpenMsg         = 1
 	UpdateMsg       = 2
diff --git a/protocols/bgp/packet/encoder.go b/protocols/bgp/packet/encoder.go
index e7c98c6f2035c5c07e681f3f062c10807fe0787e..3cfe702d14ffb66605919fe60839d98a8308b761 100644
--- a/protocols/bgp/packet/encoder.go
+++ b/protocols/bgp/packet/encoder.go
@@ -2,6 +2,7 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/taktv6/tflow2/convert"
 )
@@ -43,3 +44,62 @@ func serializeHeader(buf *bytes.Buffer, length uint16, typ uint8) {
 	buf.Write(convert.Uint16Byte(length))
 	buf.WriteByte(typ)
 }
+
+func (b *BGPUpdate) SerializeUpdate() ([]byte, error) {
+	budget := MaxLen - MinLen
+	buf := bytes.NewBuffer(nil)
+
+	withdrawBuf := bytes.NewBuffer(nil)
+	for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next {
+		nlriLen := int(withdraw.serialize(withdrawBuf))
+		budget -= nlriLen
+		if budget < 0 {
+			return nil, fmt.Errorf("update too long")
+		}
+	}
+
+	pathAttributesBuf := bytes.NewBuffer(nil)
+	for pa := b.PathAttributes; pa != nil; pa = pa.Next {
+		paLen := int(pa.serialize(pathAttributesBuf))
+		budget -= paLen
+		if budget < 0 {
+			return nil, fmt.Errorf("update too long")
+		}
+	}
+
+	nlriBuf := bytes.NewBuffer(nil)
+	for nlri := b.NLRI; nlri != nil; nlri = nlri.Next {
+		nlriLen := int(nlri.serialize(nlriBuf))
+		budget -= nlriLen
+		if budget < 0 {
+			return nil, fmt.Errorf("update too long")
+		}
+	}
+
+	withdrawnRoutesLen := withdrawBuf.Len()
+	if withdrawnRoutesLen > 65535 {
+		return nil, fmt.Errorf("Invalid Withdrawn Routes Length: %d", withdrawnRoutesLen)
+	}
+
+	totalPathAttributesLen := pathAttributesBuf.Len()
+	if totalPathAttributesLen > 65535 {
+		return nil, fmt.Errorf("Invalid Total Path Attribute Length: %d", totalPathAttributesLen)
+	}
+
+	totalLength := 2 + withdrawnRoutesLen + totalPathAttributesLen + 2 + nlriBuf.Len() + 19
+	if totalLength > 4096 {
+		return nil, fmt.Errorf("Update too long: %d bytes", totalLength)
+	}
+
+	serializeHeader(buf, uint16(totalLength), UpdateMsg)
+
+	buf.Write(convert.Uint16Byte(uint16(withdrawnRoutesLen)))
+	buf.Write(withdrawBuf.Bytes())
+
+	buf.Write(convert.Uint16Byte(uint16(totalPathAttributesLen)))
+	buf.Write(pathAttributesBuf.Bytes())
+
+	buf.Write(nlriBuf.Bytes())
+
+	return buf.Bytes(), nil
+}
diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go
index 1f478fc10ffc01c26447975ece48168735bd67b8..b9ce4f2427c97c776d11cc257bb5ae2f3b5e6a1f 100644
--- a/protocols/bgp/packet/nlri.go
+++ b/protocols/bgp/packet/nlri.go
@@ -58,3 +58,17 @@ func decodeNLRI(buf *bytes.Buffer) (*NLRI, uint8, error) {
 	nlri.IP = addr
 	return nlri, toCopy + 1, nil
 }
+
+func (n *NLRI) serialize(buf *bytes.Buffer) uint8 {
+	addr := n.IP.([4]byte)
+	nBytes := bytesInAddr(n.Pfxlen)
+
+	buf.WriteByte(n.Pfxlen)
+	buf.Write(addr[:nBytes])
+
+	return nBytes + 1
+}
+
+func bytesInAddr(pfxlen uint8) uint8 {
+	return uint8(math.Ceil(float64(pfxlen) / 8))
+}
diff --git a/protocols/bgp/packet/nlri_test.go b/protocols/bgp/packet/nlri_test.go
index e7251e41ef95499b470cdada02073c9cdacd046e..c9299e2c2dff1e42953f527837276cb193f19577 100644
--- a/protocols/bgp/packet/nlri_test.go
+++ b/protocols/bgp/packet/nlri_test.go
@@ -127,3 +127,84 @@ func TestDecodeNLRI(t *testing.T) {
 		assert.Equal(t, test.expected, res)
 	}
 }
+
+func TestBytesInAddr(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint8
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			input:    24,
+			expected: 3,
+		},
+		{
+			name:     "Test #2",
+			input:    25,
+			expected: 4,
+		},
+		{
+			name:     "Test #3",
+			input:    32,
+			expected: 4,
+		},
+		{
+			name:     "Test #4",
+			input:    0,
+			expected: 0,
+		},
+		{
+			name:     "Test #5",
+			input:    9,
+			expected: 2,
+		},
+	}
+
+	for _, test := range tests {
+		res := bytesInAddr(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %d", test.name, res)
+		}
+	}
+}
+
+func TestNLRISerialize(t *testing.T) {
+	tests := []struct {
+		name     string
+		nlri     *NLRI
+		expected []byte
+	}{
+		{
+			name: "Test #1",
+			nlri: &NLRI{
+				IP:     [4]byte{1, 2, 3, 0},
+				Pfxlen: 25,
+			},
+			expected: []byte{25, 1, 2, 3, 0},
+		},
+		{
+			name: "Test #2",
+			nlri: &NLRI{
+				IP:     [4]byte{1, 2, 3, 0},
+				Pfxlen: 24,
+			},
+			expected: []byte{24, 1, 2, 3},
+		},
+		{
+			name: "Test #3",
+			nlri: &NLRI{
+				IP:     [4]byte{100, 200, 128, 0},
+				Pfxlen: 17,
+			},
+			expected: []byte{17, 100, 200, 128},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		test.nlri.serialize(buf)
+		res := buf.Bytes()
+		assert.Equal(t, test.expected, res)
+	}
+}
diff --git a/protocols/bgp/packet/path_attribute_flags.go b/protocols/bgp/packet/path_attribute_flags.go
index 8beca7ac9dd841ae3366d50ce1752b3b177f1707..8c4b09f916dff0aa619c61c33bec0b66e1398922 100644
--- a/protocols/bgp/packet/path_attribute_flags.go
+++ b/protocols/bgp/packet/path_attribute_flags.go
@@ -44,3 +44,19 @@ func isExtendedLength(x uint8) bool {
 	}
 	return false
 }
+
+func setOptional(x uint8) uint8 {
+	return x | 128
+}
+
+func setTransitive(x uint8) uint8 {
+	return x | 64
+}
+
+func setPartial(x uint8) uint8 {
+	return x | 32
+}
+
+func setExtendedLength(x uint8) uint8 {
+	return x | 16
+}
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index b00f1599c96ec4f29ad4df54080b98a5a36ab0f7..be40ccf8ed2efbd0503bedc9d392ed3cd4cf118d 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+
+	"github.com/taktv6/tflow2/convert"
 )
 
 func decodePathAttrs(buf *bytes.Buffer, tpal uint16) (*PathAttribute, error) {
@@ -287,3 +289,112 @@ func dumpNBytes(buf *bytes.Buffer, n uint16) error {
 	}
 	return nil
 }
+
+func (pa *PathAttribute) serialize(buf *bytes.Buffer) uint8 {
+	pathAttrLen := uint8(0)
+
+	switch pa.TypeCode {
+	case OriginAttr:
+		pathAttrLen = pa.serializeOrigin(buf)
+	case ASPathAttr:
+		pathAttrLen = pa.serializeASPath(buf)
+	case NextHopAttr:
+		pathAttrLen = pa.serializeNextHop(buf)
+	case MEDAttr:
+		pathAttrLen = pa.serializeMED(buf)
+	case LocalPrefAttr:
+		pathAttrLen = pa.serializeLocalpref(buf)
+	case AtomicAggrAttr:
+		pathAttrLen = pa.serializeAtomicAggregate(buf)
+	case AggregatorAttr:
+		pathAttrLen = pa.serializeAggregator(buf)
+	}
+
+	return pathAttrLen
+}
+
+func (pa *PathAttribute) serializeOrigin(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(OriginAttr)
+	length := uint8(1)
+	buf.WriteByte(length)
+	buf.WriteByte(pa.Value.(uint8))
+	return 4
+}
+
+func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(ASPathAttr)
+	length := uint8(2)
+	asPath := pa.Value.(ASPath)
+	for _, segment := range asPath {
+		buf.WriteByte(segment.Type)
+		buf.WriteByte(uint8(len(segment.ASNs)))
+		for _, asn := range segment.ASNs {
+			buf.Write(convert.Uint16Byte(uint16(asn)))
+		}
+		length += 2 + uint8(len(segment.ASNs))*2
+	}
+
+	return length
+}
+
+func (pa *PathAttribute) serializeNextHop(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(NextHopAttr)
+	length := uint8(4)
+	buf.WriteByte(length)
+	addr := pa.Value.([4]byte)
+	buf.Write(addr[:])
+	return 7
+}
+
+func (pa *PathAttribute) serializeMED(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setOptional(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(MEDAttr)
+	length := uint8(4)
+	buf.WriteByte(length)
+	buf.Write(convert.Uint32Byte(pa.Value.(uint32)))
+	return 7
+}
+
+func (pa *PathAttribute) serializeLocalpref(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(LocalPrefAttr)
+	length := uint8(4)
+	buf.WriteByte(length)
+	buf.Write(convert.Uint32Byte(pa.Value.(uint32)))
+	return 7
+}
+
+func (pa *PathAttribute) serializeAtomicAggregate(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(AtomicAggrAttr)
+	length := uint8(0)
+	buf.WriteByte(length)
+	return 3
+}
+
+func (pa *PathAttribute) serializeAggregator(buf *bytes.Buffer) uint8 {
+	attrFlags := uint8(0)
+	attrFlags = setOptional(attrFlags)
+	attrFlags = setTransitive(attrFlags)
+	buf.WriteByte(attrFlags)
+	buf.WriteByte(AggregatorAttr)
+	length := uint8(2)
+	buf.WriteByte(length)
+	buf.Write(convert.Uint16Byte(pa.Value.(uint16)))
+	return 5
+}
diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go
index ee4d0fc3f760cef3f81b0dceaaf9a56d262afb66..052c40796d1b720fbba8c394dc3158a38725b369 100644
--- a/protocols/bgp/packet/path_attributes_test.go
+++ b/protocols/bgp/packet/path_attributes_test.go
@@ -757,3 +757,536 @@ func TestASPathString(t *testing.T) {
 		assert.Equal(t, test.expected, res)
 	}
 }
+
+func TestSetOptional(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint8
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			input:    0,
+			expected: 128,
+		},
+	}
+
+	for _, test := range tests {
+		res := setOptional(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %d", test.name, res)
+		}
+	}
+}
+
+func TestSetTransitive(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint8
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			input:    0,
+			expected: 64,
+		},
+	}
+
+	for _, test := range tests {
+		res := setTransitive(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %d", test.name, res)
+		}
+	}
+}
+
+func TestSetPartial(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint8
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			input:    0,
+			expected: 32,
+		},
+	}
+
+	for _, test := range tests {
+		res := setPartial(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %d", test.name, res)
+		}
+	}
+}
+
+func TestSetExtendedLength(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    uint8
+		expected uint8
+	}{
+		{
+			name:     "Test #1",
+			input:    0,
+			expected: 16,
+		},
+	}
+
+	for _, test := range tests {
+		res := setExtendedLength(test.input)
+		if res != test.expected {
+			t.Errorf("Unexpected result for test %q: %d", test.name, res)
+		}
+	}
+}
+
+func TestSerializeOrigin(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: OriginAttr,
+				Value:    uint8(0), // IGP
+			},
+			expectedLen: 4,
+			expected:    []byte{64, 1, 1, 0},
+		},
+		{
+			name: "Test #2",
+			input: &PathAttribute{
+				TypeCode: OriginAttr,
+				Value:    uint8(2), // INCOMPLETE
+			},
+			expectedLen: 4,
+			expected:    []byte{64, 1, 1, 2},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeOrigin(buf)
+		if test.expectedLen != n {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeNextHop(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: NextHopAttr,
+				Value:    [4]byte{100, 110, 120, 130},
+			},
+			expected:    []byte{0, 3, 4, 100, 110, 120, 130},
+			expectedLen: 7,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeNextHop(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeMED(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: MEDAttr,
+				Value:    uint32(1000),
+			},
+			expected: []byte{
+				128,          // Attribute flags
+				4,            // Type
+				4,            // Length
+				0, 0, 3, 232, // Value = 1000
+			},
+			expectedLen: 7,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeMED(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeLocalPref(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: LocalPrefAttr,
+				Value:    uint32(1000),
+			},
+			expected: []byte{
+				64,           // Attribute flags
+				5,            // Type
+				4,            // Length
+				0, 0, 3, 232, // Value = 1000
+			},
+			expectedLen: 7,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeLocalpref(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeAtomicAggregate(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: AtomicAggrAttr,
+			},
+			expected: []byte{
+				64, // Attribute flags
+				6,  // Type
+				0,  // Length
+			},
+			expectedLen: 3,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeAtomicAggregate(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeAggregator(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: AggregatorAttr,
+				Value:    uint16(174),
+			},
+			expected: []byte{
+				192,    // Attribute flags
+				7,      // Type
+				2,      // Length
+				0, 174, // Value = 174
+			},
+			expectedLen: 5,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeAggregator(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerializeASPath(t *testing.T) {
+	tests := []struct {
+		name        string
+		input       *PathAttribute
+		expected    []byte
+		expectedLen uint8
+	}{
+		{
+			name: "Test #1",
+			input: &PathAttribute{
+				TypeCode: ASPathAttr,
+				Value: ASPath{
+					{
+						Type: 2, // Sequence
+						ASNs: []uint32{
+							100, 200, 210,
+						},
+					},
+				},
+			},
+			expected: []byte{
+				64,     // Attribute flags
+				2,      // Type
+				2,      // AS_SEQUENCE
+				3,      // ASN count
+				0, 100, // ASN 100
+				0, 200, // ASN 200
+				0, 210, // ASN 210
+			},
+			expectedLen: 10,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		n := test.input.serializeASPath(buf)
+		if n != test.expectedLen {
+			t.Errorf("Unexpected length for test %q: %d", test.name, n)
+			continue
+		}
+
+		assert.Equal(t, test.expected, buf.Bytes())
+	}
+}
+
+func TestSerialize(t *testing.T) {
+	tests := []struct {
+		name     string
+		msg      *BGPUpdate
+		expected []byte
+		wantFail bool
+	}{
+		{
+			name: "Withdraw only",
+			msg: &BGPUpdate{
+				WithdrawnRoutes: &NLRI{
+					IP:     [4]byte{100, 110, 120, 0},
+					Pfxlen: 24,
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 27, // Length
+				2,    // Msg Type
+				0, 4, // Withdrawn Routes Length
+				24, 100, 110, 120, // NLRI
+				0, 0, // Total Path Attribute Length
+			},
+		},
+		{
+			name: "NLRI only",
+			msg: &BGPUpdate{
+				NLRI: &NLRI{
+					IP:     [4]byte{100, 110, 128, 0},
+					Pfxlen: 17,
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 27, // Length
+				2,    // Msg Type
+				0, 0, // Withdrawn Routes Length
+				0, 0, // Total Path Attribute Length
+				17, 100, 110, 128, // NLRI
+			},
+		},
+		{
+			name: "Path Attributes only",
+			msg: &BGPUpdate{
+				PathAttributes: &PathAttribute{
+					Optional:   true,
+					Transitive: true,
+					TypeCode:   OriginAttr,
+					Value:      uint8(0), // IGP
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 27, // Length
+				2,    // Msg Type
+				0, 0, // Withdrawn Routes Length
+				0, 4, // Total Path Attribute Length
+				64, // Attr. Flags
+				1,  // Attr. Type Code
+				1,  // Length
+				0,  // Value
+			},
+		},
+		{
+			name: "Full test",
+			msg: &BGPUpdate{
+				WithdrawnRoutes: &NLRI{
+					IP:     [4]byte{10, 0, 0, 0},
+					Pfxlen: 8,
+					Next: &NLRI{
+						IP:     [4]byte{192, 168, 0, 0},
+						Pfxlen: 16,
+					},
+				},
+				PathAttributes: &PathAttribute{
+					TypeCode: OriginAttr,
+					Value:    uint8(0),
+					Next: &PathAttribute{
+						TypeCode: ASPathAttr,
+						Value: ASPath{
+							{
+								Type: 2,
+								ASNs: []uint32{100, 155, 200},
+							},
+							{
+								Type: 1,
+								ASNs: []uint32{10, 20},
+							},
+						},
+						Next: &PathAttribute{
+							TypeCode: NextHopAttr,
+							Value:    [4]byte{10, 20, 30, 40},
+							Next: &PathAttribute{
+								TypeCode: MEDAttr,
+								Value:    uint32(100),
+								Next: &PathAttribute{
+									TypeCode: LocalPrefAttr,
+									Value:    uint32(500),
+									Next: &PathAttribute{
+										TypeCode: AtomicAggrAttr,
+										Next: &PathAttribute{
+											TypeCode: AggregatorAttr,
+											Value:    uint16(200),
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+				NLRI: &NLRI{
+					IP:     [4]byte{8, 8, 8, 0},
+					Pfxlen: 24,
+					Next: &NLRI{
+						IP:     [4]byte{185, 65, 240, 0},
+						Pfxlen: 22,
+					},
+				},
+			},
+			expected: []byte{
+				0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+				0, 85, // Length
+				2, // Msg Type
+
+				// Withdraws
+				0, 5, // Withdrawn Routes Length
+				8, 10, // Withdraw 10/8
+				16, 192, 168, // Withdraw 192.168/16
+
+				0, 49, // Total Path Attribute Length
+
+				// ORIGIN
+				64, // Attr. Flags
+				1,  // Attr. Type Code
+				1,  // Length
+				0,  // Value
+				// ASPath
+				64,                     // Attr. Flags
+				2,                      // Attr. Type Code
+				2,                      // Path Segment Type = AS_SEQUENCE
+				3,                      // Path Segment Length
+				0, 100, 0, 155, 0, 200, // ASNs
+				1,            // Path Segment Type = AS_SET
+				2,            // Path Segment Type = AS_SET
+				0, 10, 0, 20, // ASNs
+				// Next Hop
+				64,             // Attr. Flags
+				3,              // Attr. Type Code
+				4,              // Length
+				10, 20, 30, 40, // Next Hop Address
+				// MED
+				128,          // Attr. Flags
+				4,            // Attr Type Code
+				4,            // Length
+				0, 0, 0, 100, // MED = 100
+				// LocalPref
+				64,           // Attr. Flags
+				5,            // Attr. Type Code
+				4,            // Length
+				0, 0, 1, 244, // Localpref
+				// Atomic Aggregate
+				64, // Attr. Flags
+				6,  // Attr. Type Code
+				0,  // Length
+				// Aggregator
+				192,    // Attr. Flags
+				7,      // Attr. Type Code
+				2,      // Length
+				0, 200, // Aggregator ASN = 200
+
+				// NLRI
+				24, 8, 8, 8, // 8.8.8.0/24
+				22, 185, 65, 240, // 185.65.240.0/22
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res, err := test.msg.SerializeUpdate()
+		if err != nil {
+			if test.wantFail {
+				continue
+			}
+
+			t.Errorf("Unexpected failure for test %q: %v", test.name, err)
+			continue
+		}
+
+		if test.wantFail {
+			t.Errorf("Unexpected success for test %q", test.name)
+			continue
+		}
+
+		assert.Equal(t, test.expected, res)
+	}
+}