diff --git a/protocols/isis/packet/csnp.go b/protocols/isis/packet/csnp.go
index 133a196dedd304011c15ad45802fedbe3dc4777e..6e578a660b81f2d69517058f6a30f676a64a2e8b 100644
--- a/protocols/isis/packet/csnp.go
+++ b/protocols/isis/packet/csnp.go
@@ -2,6 +2,7 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 	"math"
 	"sort"
 
@@ -14,16 +15,16 @@ import (
 
 const (
 	// CSNPMinLen is the minimal length of a CSNP
-	CSNPMinLen = 24
+	CSNPMinLen = PSNPMinLen + 16
 )
 
 // CSNP represents a Complete Sequence Number PDU
 type CSNP struct {
 	PDULength  uint16
-	SourceID   [6]byte
+	SourceID   types.SourceID
 	StartLSPID LSPID
 	EndLSPID   LSPID
-	LSPEntries []LSPEntry
+	TLVs       []TLV
 }
 
 func compareLSPIDs(lspIDA, lspIDB LSPID) bool {
@@ -44,7 +45,7 @@ func compareLSPIDs(lspIDA, lspIDB LSPID) bool {
 }
 
 // NewCSNPs creates the necessary number of CSNP PDUs to carry all LSPEntries
-func NewCSNPs(sourceID types.SystemID, lspEntries []LSPEntry, maxPDULen int) []CSNP {
+func NewCSNPs(sourceID types.SourceID, lspEntries []*LSPEntry, maxPDULen int) []CSNP {
 	left := len(lspEntries)
 	lspsPerCSNP := (maxPDULen - CSNPMinLen) / LSPEntryLen
 	numCSNPs := int(math.Ceil(float64(left) / float64(lspsPerCSNP)))
@@ -71,8 +72,11 @@ func NewCSNPs(sourceID types.SystemID, lspEntries []LSPEntry, maxPDULen int) []C
 		start := i * lspsPerCSNP
 		end := umath.Min(lspsPerCSNP, left)
 
-		slice := lspEntries[start : start+end]
-		csnp := newCSNP(sourceID, slice)
+		entries := lspEntries[start : start+end]
+		tlvs := []TLV{
+			NewLSPEntriesTLV(entries),
+		}
+		csnp := newCSNP(sourceID, entries[0].LSPID, entries[len(entries)-1].LSPID, tlvs)
 		if csnp == nil {
 			continue
 		}
@@ -83,38 +87,52 @@ func NewCSNPs(sourceID types.SystemID, lspEntries []LSPEntry, maxPDULen int) []C
 	res[0].StartLSPID = LSPID{}
 	res[len(res)-1].EndLSPID = LSPID{
 		SystemID:     types.SystemID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-		PseudonodeID: 0xffff,
+		PseudonodeID: 0xff,
+		LSPNumber:    0xff,
 	}
 
 	return res
 }
 
-func newCSNP(sourceID types.SystemID, lspEntries []LSPEntry) *CSNP {
-	if len(lspEntries) == 0 {
-		return nil
+func newCSNP(sourceID types.SourceID, startLSPID LSPID, endLSPID LSPID, tlvs []TLV) *CSNP {
+	tlvsLen := uint16(0)
+	for i := range tlvs {
+		tlvsLen += uint16(tlvs[i].Length())
 	}
 
 	csnp := CSNP{
-		PDULength:  uint16(CSNPMinLen + len(lspEntries)*LSPEntryLen),
+		PDULength:  uint16(CSNPMinLen + tlvsLen),
 		SourceID:   sourceID,
-		StartLSPID: lspEntries[0].LSPID,
-		EndLSPID:   lspEntries[len(lspEntries)-1].LSPID,
-		LSPEntries: lspEntries,
+		StartLSPID: startLSPID,
+		EndLSPID:   endLSPID,
+		TLVs:       tlvs,
 	}
 
 	return &csnp
 }
 
+// GetLSPEntries returns LSP Entries from the LSP Entries TLV
+func (c *CSNP) GetLSPEntries() []*LSPEntry {
+	for _, tlv := range c.TLVs {
+		if tlv.Type() != LSPEntriesTLVType {
+			continue
+		}
+
+		return tlv.Value().(*LSPEntriesTLV).LSPEntries
+	}
+
+	return nil
+}
+
 // Serialize serializes CSNPs
 func (c *CSNP) Serialize(buf *bytes.Buffer) {
-	c.PDULength = uint16(CSNPMinLen + len(c.LSPEntries)*LSPEntryLen)
 	buf.Write(convert.Uint16Byte(c.PDULength))
-	buf.Write(c.SourceID[:])
+	buf.Write(c.SourceID.Serialize())
 	c.StartLSPID.Serialize(buf)
 	c.EndLSPID.Serialize(buf)
 
-	for _, lspEntry := range c.LSPEntries {
-		lspEntry.Serialize(buf)
+	for i := range c.TLVs {
+		c.TLVs[i].Serialize(buf)
 	}
 }
 
@@ -127,24 +145,22 @@ func DecodeCSNP(buf *bytes.Buffer) (*CSNP, error) {
 		&csnp.SourceID,
 		&csnp.StartLSPID.SystemID,
 		&csnp.StartLSPID.PseudonodeID,
+		&csnp.StartLSPID.LSPNumber,
 		&csnp.EndLSPID.SystemID,
 		&csnp.EndLSPID.PseudonodeID,
+		&csnp.EndLSPID.LSPNumber,
 	}
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
-	nEntries := (csnp.PDULength - CSNPMinLen) / LSPEntryLen
-	csnp.LSPEntries = make([]LSPEntry, nEntries)
-	for i := uint16(0); i < nEntries; i++ {
-		lspEntry, err := decodeLSPEntry(buf)
-		if err != nil {
-			return nil, errors.Wrap(err, "Unable to get LSPEntries")
-		}
-		csnp.LSPEntries[i] = *lspEntry
+	tlvs, err := readTLVs(buf)
+	if err != nil {
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
+	csnp.TLVs = tlvs
 	return csnp, nil
 }
diff --git a/protocols/isis/packet/csnp_test.go b/protocols/isis/packet/csnp_test.go
index 4d967e28120e81e74fadfc1af3190c5010ed5dd1..a47761a4fbec8bb4e37fe6351ee4af6e165637f7 100644
--- a/protocols/isis/packet/csnp_test.go
+++ b/protocols/isis/packet/csnp_test.go
@@ -8,18 +8,62 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func TestGetLSPEntries(t *testing.T) {
+	tests := []struct {
+		name     string
+		csnp     *CSNP
+		expected []*LSPEntry
+	}{
+		{
+			name: "Test #1",
+			csnp: &CSNP{
+				TLVs: []TLV{
+					&LSPEntriesTLV{
+						TLVType: LSPEntriesTLVType,
+						LSPEntries: []*LSPEntry{
+							{
+								SequenceNumber: 123,
+							},
+						},
+					},
+				},
+			},
+			expected: []*LSPEntry{
+				{
+					SequenceNumber: 123,
+				},
+			},
+		},
+		{
+			name: "TLV not found",
+			csnp: &CSNP{
+				TLVs: []TLV{},
+			},
+			expected: nil,
+		},
+	}
+
+	for _, test := range tests {
+		res := test.csnp.GetLSPEntries()
+		assert.Equalf(t, test.expected, res, "Test %q", test.name)
+	}
+}
+
 func TestNewCSNPs(t *testing.T) {
 	tests := []struct {
 		name         string
-		sourceID     types.SystemID
-		lspEntries   []LSPEntry
+		sourceID     types.SourceID
+		lspEntries   []*LSPEntry
 		maxPDULength int
 		expected     []CSNP
 	}{
 		{
-			name:     "All in one packet",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "All in one packet",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1000,
 					RemainingLifetime: 2000,
@@ -33,21 +77,31 @@ func TestNewCSNPs(t *testing.T) {
 			maxPDULength: 1492,
 			expected: []CSNP{
 				{
-					PDULength:  40,
-					SourceID:   types.SystemID{10, 20, 30, 40, 50, 60},
+					PDULength: 49,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
 					StartLSPID: LSPID{},
 					EndLSPID: LSPID{
 						SystemID:     types.SystemID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-						PseudonodeID: 0xffff,
+						PseudonodeID: 0xff,
+						LSPNumber:    0xff,
 					},
-					LSPEntries: []LSPEntry{
-						{
-							SequenceNumber:    1000,
-							RemainingLifetime: 2000,
-							LSPChecksum:       111,
-							LSPID: LSPID{
-								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-								PseudonodeID: 123,
+					TLVs: []TLV{
+						&LSPEntriesTLV{
+							TLVType:   LSPEntriesTLVType,
+							TLVLength: 16,
+							LSPEntries: []*LSPEntry{
+								{
+									SequenceNumber:    1000,
+									RemainingLifetime: 2000,
+									LSPChecksum:       111,
+									LSPID: LSPID{
+										SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+										PseudonodeID: 123,
+									},
+								},
 							},
 						},
 					},
@@ -55,9 +109,12 @@ func TestNewCSNPs(t *testing.T) {
 			},
 		},
 		{
-			name:     "2 packets",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "2 packets",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1001,
 					RemainingLifetime: 2001,
@@ -77,47 +134,67 @@ func TestNewCSNPs(t *testing.T) {
 					},
 				},
 			},
-			maxPDULength: 40,
+			maxPDULength: 49,
 			expected: []CSNP{
 				{
-					PDULength:  40,
-					SourceID:   types.SystemID{10, 20, 30, 40, 50, 60},
+					PDULength: 49,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
 					StartLSPID: LSPID{},
 					EndLSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 100,
 					},
-					LSPEntries: []LSPEntry{
-						{
-							SequenceNumber:    1000,
-							RemainingLifetime: 2000,
-							LSPChecksum:       111,
-							LSPID: LSPID{
-								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-								PseudonodeID: 100,
+					TLVs: []TLV{
+						&LSPEntriesTLV{
+							TLVType:   LSPEntriesTLVType,
+							TLVLength: 16,
+							LSPEntries: []*LSPEntry{
+								{
+									SequenceNumber:    1000,
+									RemainingLifetime: 2000,
+									LSPChecksum:       111,
+									LSPID: LSPID{
+										SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+										PseudonodeID: 100,
+									},
+								},
 							},
 						},
 					},
 				},
 				{
-					PDULength: 40,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					PDULength: 49,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
 					StartLSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 200,
 					},
 					EndLSPID: LSPID{
 						SystemID:     types.SystemID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-						PseudonodeID: 0xffff,
+						PseudonodeID: 0xff,
+						LSPNumber:    0xff,
 					},
-					LSPEntries: []LSPEntry{
-						{
-							SequenceNumber:    1001,
-							RemainingLifetime: 2001,
-							LSPChecksum:       112,
-							LSPID: LSPID{
-								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-								PseudonodeID: 200,
+					TLVs: []TLV{
+						&LSPEntriesTLV{
+
+							TLVType:   LSPEntriesTLVType,
+							TLVLength: 16,
+							LSPEntries: []*LSPEntry{
+								{
+									SequenceNumber:    1001,
+									RemainingLifetime: 2001,
+									LSPChecksum:       112,
+									LSPID: LSPID{
+										SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+										PseudonodeID: 200,
+									},
+								},
 							},
 						},
 					},
@@ -125,9 +202,12 @@ func TestNewCSNPs(t *testing.T) {
 			},
 		},
 		{
-			name:     "2 packets with odd pdu length",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "2 packets with odd pdu length",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1001,
 					RemainingLifetime: 2001,
@@ -147,47 +227,66 @@ func TestNewCSNPs(t *testing.T) {
 					},
 				},
 			},
-			maxPDULength: 41,
+			maxPDULength: 55,
 			expected: []CSNP{
 				{
-					PDULength:  40,
-					SourceID:   types.SystemID{10, 20, 30, 40, 50, 60},
+					PDULength: 49,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
 					StartLSPID: LSPID{},
 					EndLSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 100,
 					},
-					LSPEntries: []LSPEntry{
-						{
-							SequenceNumber:    1000,
-							RemainingLifetime: 2000,
-							LSPChecksum:       111,
-							LSPID: LSPID{
-								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-								PseudonodeID: 100,
+					TLVs: []TLV{
+						&LSPEntriesTLV{
+							TLVType:   LSPEntriesTLVType,
+							TLVLength: 16,
+							LSPEntries: []*LSPEntry{
+								{
+									SequenceNumber:    1000,
+									RemainingLifetime: 2000,
+									LSPChecksum:       111,
+									LSPID: LSPID{
+										SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+										PseudonodeID: 100,
+									},
+								},
 							},
 						},
 					},
 				},
 				{
-					PDULength: 40,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					PDULength: 49,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
 					StartLSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 200,
 					},
 					EndLSPID: LSPID{
 						SystemID:     types.SystemID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-						PseudonodeID: 0xffff,
+						PseudonodeID: 0xff,
+						LSPNumber:    0xff,
 					},
-					LSPEntries: []LSPEntry{
-						{
-							SequenceNumber:    1001,
-							RemainingLifetime: 2001,
-							LSPChecksum:       112,
-							LSPID: LSPID{
-								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-								PseudonodeID: 200,
+					TLVs: []TLV{
+						&LSPEntriesTLV{
+							TLVType:   LSPEntriesTLVType,
+							TLVLength: 16,
+							LSPEntries: []*LSPEntry{
+								{
+									SequenceNumber:    1001,
+									RemainingLifetime: 2001,
+									LSPChecksum:       112,
+									LSPID: LSPID{
+										SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+										PseudonodeID: 200,
+									},
+								},
 							},
 						},
 					},
@@ -211,36 +310,51 @@ func TestCSNPSerialize(t *testing.T) {
 		{
 			name: "Test #1",
 			csnp: CSNP{
-				SourceID: types.SystemID{10, 20, 30, 40, 50, 60},
+				PDULength: 43,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
 				StartLSPID: LSPID{
-					SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-					PseudonodeID: 256,
+					SystemID:     types.SystemID{0x11, 0x22, 0x33, 0x44, 0x55, 0x66},
+					PseudonodeID: 0,
+					LSPNumber:    0,
 				},
 				EndLSPID: LSPID{
-					SystemID:     types.SystemID{11, 22, 33, 44, 55, 67},
-					PseudonodeID: 255,
+					SystemID:     types.SystemID{0x11, 0x22, 0x33, 0x44, 0x55, 0x67},
+					PseudonodeID: 0xff,
+					LSPNumber:    0,
 				},
-				LSPEntries: []LSPEntry{
-					{
-						SequenceNumber:    123,
-						RemainingLifetime: 255,
-						LSPChecksum:       111,
-						LSPID: LSPID{
-							SystemID:     types.SystemID{10, 20, 30, 40, 50, 61},
-							PseudonodeID: 11,
+				TLVs: []TLV{
+					&LSPEntriesTLV{
+						TLVType:   LSPEntriesTLVType,
+						TLVLength: 16,
+						LSPEntries: []*LSPEntry{
+							{
+								RemainingLifetime: 255,
+								LSPID: LSPID{
+									SystemID:     types.SystemID{10, 20, 30, 40, 50, 61},
+									PseudonodeID: 11,
+									LSPNumber:    0,
+								},
+								SequenceNumber: 123,
+								LSPChecksum:    111,
+							},
 						},
 					},
 				},
 			},
 			expected: []byte{
-				0, 40,
-				10, 20, 30, 40, 50, 60,
-				11, 22, 33, 44, 55, 66, 1, 0,
-				11, 22, 33, 44, 55, 67, 0, 255,
-				0, 0, 0, 123,
-				0, 255,
-				0, 111,
-				10, 20, 30, 40, 50, 61, 0, 11,
+				0, 43, // Length
+				10, 20, 30, 40, 50, 60, 0, // SourceID
+				0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0, 0, // Start LDP ID
+				0x11, 0x22, 0x33, 0x44, 0x55, 0x67, 0xff, 0, // End LSP ID
+				9,      // TLV Type
+				16,     // TLV Length
+				0, 255, // Remaining Lifetime
+				10, 20, 30, 40, 50, 61, 11, 0, // LSP ID
+				0, 0, 0, 123, // Seq. Nr.
+				0, 111, // Checksum
 			},
 		},
 	}
@@ -262,8 +376,8 @@ func TestDecodeCSNP(t *testing.T) {
 		{
 			name: "Incomplete CSNP",
 			input: []byte{
-				0, 24, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 25, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 				11, 22, 33, 44, 55, 66, 0, 100,
 				11, 22, 33, 77, 88, 0, 0,
 			},
@@ -272,8 +386,8 @@ func TestDecodeCSNP(t *testing.T) {
 		{
 			name: "Incomplete CSNP LSPEntry",
 			input: []byte{
-				0, 40, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 41, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 				0, 0, 0, 20, // Sequence Number
 				11, 22, 33, 44, 55, 66, 0, 100,
 				11, 22, 33, 77, 88, 0, 0, 200,
@@ -284,36 +398,50 @@ func TestDecodeCSNP(t *testing.T) {
 		{
 			name: "CSNP with one LSPEntry",
 			input: []byte{
-				0, 40, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 41, // PDU Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 				11, 22, 33, 44, 55, 66, 0, 100, // StartLSPID
-				11, 22, 33, 77, 88, 0, 0, 200, // EndLSPID
-				0, 0, 0, 20, // Sequence Number
+				11, 22, 33, 77, 88, 99, 0, 200, // EndLSPID
+				9,    // TLV Type
+				16,   // TLV Length
 				1, 0, // Remaining Lifetime
-				2, 0, // Checksum
 				11, 22, 33, 44, 55, 66, // SystemID
 				0, 20, // Pseudonode ID
+				0, 0, 0, 20, // Sequence Number
+				2, 0, // Checksum
 			},
 			wantFail: false,
 			expected: &CSNP{
-				PDULength: 40,
-				SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				PDULength: 41,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
 				StartLSPID: LSPID{
 					SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-					PseudonodeID: 100,
+					PseudonodeID: 0,
+					LSPNumber:    100,
 				},
 				EndLSPID: LSPID{
-					SystemID:     types.SystemID{11, 22, 33, 77, 88, 0},
-					PseudonodeID: 200,
+					SystemID:     types.SystemID{11, 22, 33, 77, 88, 99},
+					PseudonodeID: 0,
+					LSPNumber:    200,
 				},
-				LSPEntries: []LSPEntry{
-					{
-						SequenceNumber:    20,
-						RemainingLifetime: 256,
-						LSPChecksum:       512,
-						LSPID: LSPID{
-							SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-							PseudonodeID: 20,
+				TLVs: []TLV{
+					&LSPEntriesTLV{
+						TLVType:   LSPEntriesTLVType,
+						TLVLength: 16,
+						LSPEntries: []*LSPEntry{
+							{
+								SequenceNumber:    20,
+								RemainingLifetime: 256,
+								LSPChecksum:       512,
+								LSPID: LSPID{
+									SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
+									PseudonodeID: 0,
+									LSPNumber:    20,
+								},
+							},
 						},
 					},
 				},
@@ -322,50 +450,65 @@ func TestDecodeCSNP(t *testing.T) {
 		{
 			name: "PSNP with two LSPEntries",
 			input: []byte{
-				0, 58, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 59, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 				11, 22, 33, 44, 55, 66, 0, 100, // StartLSPID
 				11, 22, 33, 77, 88, 0, 0, 200, // EndLSPID
-				0, 0, 0, 20, // Sequence Number
+				9,    // TLV Type
+				32,   // TLV Length
 				1, 0, // Remaining Lifetime
-				2, 0, // Checksum
 				11, 22, 33, 44, 55, 66, // SystemID
 				0, 20, // Pseudonode ID
-				0, 0, 0, 21, // Sequence Number
-				2, 0, // Remaining Lifetime
+				0, 0, 0, 20, // Sequence Number
 				2, 0, // Checksum
+				2, 0, // Remaining Lifetime
 				11, 22, 33, 44, 55, 67, // SystemID
 				0, 21, // Pseudonode ID
+				0, 0, 0, 21, // Sequence Number
+				2, 0, // Checksum
 			},
 			wantFail: false,
 			expected: &CSNP{
-				PDULength: 58,
-				SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				PDULength: 59,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
 				StartLSPID: LSPID{
 					SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-					PseudonodeID: 100,
+					PseudonodeID: 0,
+					LSPNumber:    100,
 				},
 				EndLSPID: LSPID{
 					SystemID:     types.SystemID{11, 22, 33, 77, 88, 0},
-					PseudonodeID: 200,
+					PseudonodeID: 0,
+					LSPNumber:    200,
 				},
-				LSPEntries: []LSPEntry{
-					{
-						SequenceNumber:    20,
-						RemainingLifetime: 256,
-						LSPChecksum:       512,
-						LSPID: LSPID{
-							SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-							PseudonodeID: 20,
-						},
-					},
-					{
-						SequenceNumber:    21,
-						RemainingLifetime: 512,
-						LSPChecksum:       512,
-						LSPID: LSPID{
-							SystemID:     types.SystemID{11, 22, 33, 44, 55, 67},
-							PseudonodeID: 21,
+				TLVs: []TLV{
+					&LSPEntriesTLV{
+						TLVType:   LSPEntriesTLVType,
+						TLVLength: 32,
+						LSPEntries: []*LSPEntry{
+							{
+								SequenceNumber:    20,
+								RemainingLifetime: 256,
+								LSPChecksum:       512,
+								LSPID: LSPID{
+									SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
+									PseudonodeID: 0,
+									LSPNumber:    20,
+								},
+							},
+							{
+								SequenceNumber:    21,
+								RemainingLifetime: 512,
+								LSPChecksum:       512,
+								LSPID: LSPID{
+									SystemID:     types.SystemID{11, 22, 33, 44, 55, 67},
+									PseudonodeID: 0,
+									LSPNumber:    21,
+								},
+							},
 						},
 					},
 				},
diff --git a/protocols/isis/packet/header.go b/protocols/isis/packet/header.go
index 8ff00ed2c4fc16987bc557e7ac10ef9fc93b9061..475087eda962b7b06229f094c7d97926e3c8f331 100644
--- a/protocols/isis/packet/header.go
+++ b/protocols/isis/packet/header.go
@@ -2,9 +2,13 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
-	"github.com/pkg/errors"
+)
+
+const (
+	HeaderLen = 8
 )
 
 // ISISHeader represents an ISIS header
@@ -42,7 +46,7 @@ func DecodeHeader(buf *bytes.Buffer) (*ISISHeader, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return h, nil
diff --git a/protocols/isis/packet/hello.go b/protocols/isis/packet/hello.go
index db3c2a27a26487319b2c125d9595535102773fd2..910042b2e66b1ece730edff86808b7fd27e2eb41 100644
--- a/protocols/isis/packet/hello.go
+++ b/protocols/isis/packet/hello.go
@@ -2,11 +2,11 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 // L2Hello represents a broadcast L2 hello
@@ -31,11 +31,62 @@ type P2PHello struct {
 }
 
 const (
-	P2PHelloMinSize = 20
-	ISISHeaderSize  = 8
-	L2CircuitType   = 2
+	P2PHelloMinLen = 20
+	ISISHeaderLen  = 8
+	L2CircuitType  = 2
 )
 
+// GetProtocolsSupportedTLV gets the protocols supported TLV
+func (h *P2PHello) GetProtocolsSupportedTLV() *ProtocolsSupportedTLV {
+	for _, tlv := range h.TLVs {
+		if tlv.Type() != ProtocolsSupportedTLVType {
+			continue
+		}
+
+		return tlv.(*ProtocolsSupportedTLV)
+	}
+
+	return nil
+}
+
+// GetAreaAddressesTLV gets the area addresses TLV
+func (h *P2PHello) GetAreaAddressesTLV() *AreaAddressesTLV {
+	for _, tlv := range h.TLVs {
+		if tlv.Type() != AreaAddressesTLVType {
+			continue
+		}
+
+		return tlv.(*AreaAddressesTLV)
+	}
+
+	return nil
+}
+
+// GetP2PAdjTLV gets the P2P Adjacency TLV from the P2P Hello
+func (h *P2PHello) GetP2PAdjTLV() *P2PAdjacencyStateTLV {
+	for _, tlv := range h.TLVs {
+		if tlv.Type() != P2PAdjacencyStateTLVType {
+			continue
+		}
+
+		return tlv.(*P2PAdjacencyStateTLV)
+	}
+
+	return nil
+}
+
+// GetIPInterfaceAddressesesTLV gets the IP Interface Addresses TLV
+func (h *P2PHello) GetIPInterfaceAddressesesTLV() *IPInterfaceAddressesTLV {
+	for _, tlv := range h.TLVs {
+		if tlv.Type() != IPInterfaceAddressesTLVType {
+			continue
+		}
+
+		return tlv.(*IPInterfaceAddressesTLV)
+	}
+	return nil
+}
+
 // Serialize serializes a P2P Hello
 func (h *P2PHello) Serialize(buf *bytes.Buffer) {
 	buf.WriteByte(h.CircuitType)
@@ -63,12 +114,12 @@ func DecodeP2PHello(buf *bytes.Buffer) (*P2PHello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to read TLVs")
+		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
 	}
 
 	pdu.TLVs = TLVs
@@ -91,12 +142,12 @@ func DecodeL2Hello(buf *bytes.Buffer) (*L2Hello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to read TLVs")
+		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/hello_test.go b/protocols/isis/packet/hello_test.go
index 661c489a236203be3d586d692541902af1486ceb..2f3fa776bfd6ed3844a84620f3add4f06c849082 100644
--- a/protocols/isis/packet/hello_test.go
+++ b/protocols/isis/packet/hello_test.go
@@ -8,6 +8,74 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func TestGetIPInterfaceAddressesesTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		hello    *P2PHello
+		expected *IPInterfaceAddressesTLV
+	}{
+		{
+			name: "Test #1",
+			hello: &P2PHello{
+				TLVs: []TLV{
+					NewIPInterfaceAddressesTLV([]uint32{111}),
+				},
+			},
+			expected: &IPInterfaceAddressesTLV{
+				TLVType:       IPInterfaceAddressesTLVType,
+				TLVLength:     4,
+				IPv4Addresses: []uint32{111},
+			},
+		},
+		{
+			name: "Test #1",
+			hello: &P2PHello{
+				TLVs: []TLV{},
+			},
+			expected: nil,
+		},
+	}
+
+	for _, test := range tests {
+		ret := test.hello.GetIPInterfaceAddressesesTLV()
+		assert.Equalf(t, test.expected, ret, "Test %q", test.name)
+	}
+}
+
+func TestGetP2PAdjTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		hello    *P2PHello
+		expected *P2PAdjacencyStateTLV
+	}{
+		{
+			name: "Test #1",
+			hello: &P2PHello{
+				TLVs: []TLV{
+					&P2PAdjacencyStateTLV{
+						TLVType: P2PAdjacencyStateTLVType,
+					},
+				},
+			},
+			expected: &P2PAdjacencyStateTLV{
+				TLVType: P2PAdjacencyStateTLVType,
+			},
+		},
+		{
+			name: "Test #1",
+			hello: &P2PHello{
+				TLVs: []TLV{},
+			},
+			expected: nil,
+		},
+	}
+
+	for _, test := range tests {
+		ret := test.hello.GetP2PAdjTLV()
+		assert.Equalf(t, test.expected, ret, "Test %q", test.name)
+	}
+}
+
 func TestP2PHelloSerialize(t *testing.T) {
 	tests := []struct {
 		name     string
@@ -240,10 +308,10 @@ func TestDecodeISISHello(t *testing.T) {
 						TLVLength:               2,
 						NetworkLayerProtocolIDs: []byte{0xcc, 0x8e},
 					},
-					&IPInterfaceAddressTLV{
-						TLVType:     132,
-						TLVLength:   4,
-						IPv4Address: 167772160,
+					&IPInterfaceAddressesTLV{
+						TLVType:       132,
+						TLVLength:     4,
+						IPv4Addresses: []uint32{167772160},
 					},
 					&AreaAddressesTLV{
 						TLVType:   1,
diff --git a/protocols/isis/packet/isis.go b/protocols/isis/packet/isis.go
index d433cd987334314560aad0ae9f8f8948e85ff71a..8e1438c253f00310c3395c2cb94479dac6f154f8 100644
--- a/protocols/isis/packet/isis.go
+++ b/protocols/isis/packet/isis.go
@@ -2,8 +2,7 @@ package packet
 
 import (
 	"bytes"
-
-	"github.com/pkg/errors"
+	"fmt"
 )
 
 const (
@@ -34,7 +33,7 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 
 	hdr, err := DecodeHeader(buf)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode header")
+		return nil, fmt.Errorf("Unable to decode header: %v", err)
 	}
 	pkt.Header = hdr
 
@@ -42,9 +41,27 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 	case P2P_HELLO:
 		p2pHello, err := DecodeP2PHello(buf)
 		if err != nil {
-			return nil, errors.Wrap(err, "Unable to decode P2P hello")
+			return nil, fmt.Errorf("Unable to decode P2P hello: %v", err)
 		}
 		pkt.Body = p2pHello
+	case L2_LS_PDU_TYPE:
+		lspdu, err := DecodeLSPDU(buf)
+		if err != nil {
+			return nil, fmt.Errorf("Unable to decode LSPDU: %v", err)
+		}
+		pkt.Body = lspdu
+	case L2_CSNP_TYPE:
+		csnp, err := DecodeCSNP(buf)
+		if err != nil {
+			return nil, fmt.Errorf("Unable to decode CSNP: %v", err)
+		}
+		pkt.Body = csnp
+	case L2_PSNP_TYPE:
+		psnp, err := DecodePSNP(buf)
+		if err != nil {
+			return nil, fmt.Errorf("Unable to decode PSNP: %v", err)
+		}
+		pkt.Body = psnp
 	}
 
 	return pkt, nil
diff --git a/protocols/isis/packet/isis_test.go b/protocols/isis/packet/isis_test.go
index 4da6163a2ab758d49d5986e583caceef8ddd57ea..31f8038a5a63f63664df2e9ff93db8f04bd26fba 100644
--- a/protocols/isis/packet/isis_test.go
+++ b/protocols/isis/packet/isis_test.go
@@ -76,10 +76,10 @@ func TestDecode(t *testing.T) {
 							TLVLength:               2,
 							NetworkLayerProtocolIDs: []uint8{0xcc, 0x8e},
 						},
-						&IPInterfaceAddressTLV{
-							TLVType:     132,
-							TLVLength:   4,
-							IPv4Address: 3232235776,
+						&IPInterfaceAddressesTLV{
+							TLVType:       132,
+							TLVLength:     4,
+							IPv4Addresses: []uint32{3232235776},
 						},
 						&AreaAddressesTLV{
 							TLVType:   1,
diff --git a/protocols/isis/packet/lsp.go b/protocols/isis/packet/lsp.go
index 6416c29af79c4362671fcbac01bbb7e904df90f7..63a38a0db7874bc595d25686a39dc2fdb6434858 100644
--- a/protocols/isis/packet/lsp.go
+++ b/protocols/isis/packet/lsp.go
@@ -2,29 +2,59 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
-	"github.com/FMNSSun/libhash/fletcher"
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/bio-routing/bio-rd/util/math"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 const (
 	LSPIDLen    = 8
 	LSPDUMinLen = 19
+	MODX        = 5802
 )
 
 // LSPID represents a Link State Packet ID
 type LSPID struct {
 	SystemID     types.SystemID
-	PseudonodeID uint16
+	PseudonodeID uint8
+	LSPNumber    uint8
+}
+
+func (l *LSPID) String() string {
+	return fmt.Sprintf("%02d%02d%02d.%02d%02d%02d.%02d-%02d", l.SystemID[0], l.SystemID[1], l.SystemID[2], l.SystemID[3], l.SystemID[4], l.SystemID[5], l.PseudonodeID, l.LSPNumber)
 }
 
 // Serialize serializes an LSPID
 func (l *LSPID) Serialize(buf *bytes.Buffer) {
 	buf.Write(l.SystemID[:])
-	buf.Write(convert.Uint16Byte(l.PseudonodeID))
+	buf.WriteByte(l.PseudonodeID)
+	buf.WriteByte(l.LSPNumber)
+}
+
+// Compare returns 1 if l is bigger m, 0 if they are equal, else -1
+func (l *LSPID) Compare(m LSPID) int {
+	for i := 0; i < 6; i++ {
+		if l.SystemID[i] > m.SystemID[i] {
+			return 1
+		}
+
+		if l.SystemID[i] < m.SystemID[i] {
+			return -1
+		}
+	}
+
+	if l.PseudonodeID > m.PseudonodeID {
+		return 1
+	}
+
+	if l.PseudonodeID < m.PseudonodeID {
+		return -1
+	}
+
+	return 0
 }
 
 // LSPDU represents a link state PDU
@@ -38,22 +68,60 @@ type LSPDU struct {
 	TLVs              []TLV
 }
 
+// UpdateLength updates the length of the LSPDU
+func (l *LSPDU) updateLength() {
+	l.Length = LSPDUMinLen + HeaderLen
+	for i := range l.TLVs {
+		l.Length += 2 + uint16(l.TLVs[i].Length())
+	}
+}
+
+func csum(input []byte) uint16 {
+	x := 0
+	y := 0
+	c0 := 0
+	c1 := 0
+	partialLen := 0
+	i := 0
+	left := len(input)
+
+	for left != 0 {
+		partialLen = math.Min(left, MODX)
+
+		for i = 0; i < partialLen; i++ {
+			c0 = c0 + int(input[i])
+			c1 += c0
+		}
+
+		c0 = c0 % 255
+		c1 = c1 % 255
+
+		left -= partialLen
+	}
+
+	z := ((len(input)-12-1)*c0 - c1)
+	x = int(z % 255)
+
+	if x < 0 {
+		x += 255
+	}
+
+	y = 510 - c0 - x
+	if y > 255 {
+		y -= 255
+	}
+	return (uint16(x) << 8) | (uint16(y) & 0xFF)
+}
+
 // SetChecksum sets the checksum of an LSPDU
 func (l *LSPDU) SetChecksum() {
 	buf := bytes.NewBuffer(nil)
-	l.Serialize(buf)
-
-	x := fletcher.New16()
-	x.Write(buf.Bytes())
-	csum := x.Sum([]byte{})
-
-	l.Checksum = uint16(csum[0])*256 + uint16(csum[1])
+	l.SerializeChecksumRelevant(buf)
+	l.Checksum = csum(buf.Bytes())
 }
 
-// Serialize serializes a linke state PDU
-func (l *LSPDU) Serialize(buf *bytes.Buffer) {
-	buf.Write(convert.Uint16Byte(l.Length))
-	buf.Write(convert.Uint16Byte(l.RemainingLifetime))
+// SerializeChecksumRelevant serializes all fields after the Remaining Lifetime field.
+func (l *LSPDU) SerializeChecksumRelevant(buf *bytes.Buffer) {
 	l.LSPID.Serialize(buf)
 	buf.Write(convert.Uint32Byte(l.SequenceNumber))
 	buf.Write(convert.Uint16Byte(l.Checksum))
@@ -64,6 +132,13 @@ func (l *LSPDU) Serialize(buf *bytes.Buffer) {
 	}
 }
 
+// Serialize serializes a linke state PDU
+func (l *LSPDU) Serialize(buf *bytes.Buffer) {
+	buf.Write(convert.Uint16Byte(l.Length))
+	buf.Write(convert.Uint16Byte(l.RemainingLifetime))
+	l.SerializeChecksumRelevant(buf)
+}
+
 // DecodeLSPDU decodes an LSPDU
 func DecodeLSPDU(buf *bytes.Buffer) (*LSPDU, error) {
 	pdu := &LSPDU{}
@@ -73,6 +148,7 @@ func DecodeLSPDU(buf *bytes.Buffer) (*LSPDU, error) {
 		&pdu.RemainingLifetime,
 		&pdu.LSPID.SystemID,
 		&pdu.LSPID.PseudonodeID,
+		&pdu.LSPID.LSPNumber,
 		&pdu.SequenceNumber,
 		&pdu.Checksum,
 		&pdu.TypeBlock,
@@ -80,12 +156,12 @@ func DecodeLSPDU(buf *bytes.Buffer) (*LSPDU, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to read TLVs")
+		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/lsp_entry.go b/protocols/isis/packet/lsp_entry.go
index 707fa918aa11e620bfb9b66bc52c6823389a1702..f81df25cb93ee835bc61e74835e7db6b46cb0a41 100644
--- a/protocols/isis/packet/lsp_entry.go
+++ b/protocols/isis/packet/lsp_entry.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 const (
@@ -15,34 +15,35 @@ const (
 
 // LSPEntry represents an LSP entry in a CSNP PDU
 type LSPEntry struct {
-	SequenceNumber    uint32
 	RemainingLifetime uint16
-	LSPChecksum       uint16
 	LSPID             LSPID
+	SequenceNumber    uint32
+	LSPChecksum       uint16
 }
 
 // Serialize serializes an LSPEntry
 func (l *LSPEntry) Serialize(buf *bytes.Buffer) {
-	buf.Write(convert.Uint32Byte(l.SequenceNumber))
 	buf.Write(convert.Uint16Byte(l.RemainingLifetime))
-	buf.Write(convert.Uint16Byte(l.LSPChecksum))
 	l.LSPID.Serialize(buf)
+	buf.Write(convert.Uint32Byte(l.SequenceNumber))
+	buf.Write(convert.Uint16Byte(l.LSPChecksum))
 }
 
 func decodeLSPEntry(buf *bytes.Buffer) (*LSPEntry, error) {
 	lspEntry := &LSPEntry{}
 
 	fields := []interface{}{
-		&lspEntry.SequenceNumber,
 		&lspEntry.RemainingLifetime,
-		&lspEntry.LSPChecksum,
 		&lspEntry.LSPID.SystemID,
 		&lspEntry.LSPID.PseudonodeID,
+		&lspEntry.LSPID.LSPNumber,
+		&lspEntry.SequenceNumber,
+		&lspEntry.LSPChecksum,
 	}
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return lspEntry, nil
diff --git a/protocols/isis/packet/lsp_test.go b/protocols/isis/packet/lsp_test.go
index c4915aba635d702c57f9ee6938633c02c2955bd8..3b125aafc5693ed7d319f5582a0cb5965bb5c6d6 100644
--- a/protocols/isis/packet/lsp_test.go
+++ b/protocols/isis/packet/lsp_test.go
@@ -8,72 +8,76 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
-func TestSerializeLSPDU(t *testing.T) {
+func TestLSPIDCompare(t *testing.T) {
 	tests := []struct {
 		name     string
-		lspdu    *LSPDU
-		expected []byte
+		a        LSPID
+		b        LSPID
+		expected int
 	}{
 		{
-			name: "Test without TLVs",
-			lspdu: &LSPDU{
-				Length:            512,
-				RemainingLifetime: 255,
-				LSPID: LSPID{
-					SystemID:     types.SystemID{1, 2, 3, 4, 5, 6},
-					PseudonodeID: 0,
-				},
-				SequenceNumber: 200,
-				Checksum:       100,
-				TypeBlock:      55,
-				TLVs:           make([]TLV, 0),
+			name:     "Test #1",
+			a:        LSPID{},
+			b:        LSPID{},
+			expected: 0,
+		},
+		{
+			name: "Test #2",
+			a: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 6},
+				PseudonodeID: 100,
 			},
-			expected: []byte{
-				2, 0,
-				0, 255,
-				1, 2, 3, 4, 5, 6, 0, 0,
-				0, 0, 0, 200,
-				0, 100,
-				55,
+			b: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 100,
 			},
+			expected: -1,
 		},
 		{
-			name: "Test with TLV",
-			lspdu: &LSPDU{
-				Length:            512,
-				RemainingLifetime: 255,
-				LSPID: LSPID{
-					SystemID:     types.SystemID{1, 2, 3, 4, 5, 6},
-					PseudonodeID: 0,
-				},
-				SequenceNumber: 200,
-				Checksum:       100,
-				TypeBlock:      55,
-				TLVs: []TLV{
-					NewPaddingTLV(2),
-				},
+			name: "Test #3",
+			a: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 8},
+				PseudonodeID: 100,
 			},
-			expected: []byte{
-				2, 0,
-				0, 255,
-				1, 2, 3, 4, 5, 6, 0, 0,
-				0, 0, 0, 200,
-				0, 100,
-				55,
-				8, 2,
-				0, 0,
+			b: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 100,
+			},
+			expected: 1,
+		},
+		{
+			name: "Test #4",
+			a: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 101,
+			},
+			b: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 100,
+			},
+			expected: 1,
+		},
+		{
+			name: "Test #4",
+			a: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 101,
+			},
+			b: LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 7},
+				PseudonodeID: 102,
 			},
+			expected: -1,
 		},
 	}
 
 	for _, test := range tests {
-		buf := bytes.NewBuffer(nil)
-		test.lspdu.Serialize(buf)
-		assert.Equalf(t, test.expected, buf.Bytes(), "Unexpected result in test %q", test.name)
+		res := test.a.Compare(test.b)
+		assert.Equalf(t, test.expected, res, "Test %q", test.name)
 	}
 }
 
-func TestSetChecksum(t *testing.T) {
+func TestSerializeLSPDU(t *testing.T) {
 	tests := []struct {
 		name     string
 		lspdu    *LSPDU
@@ -89,6 +93,7 @@ func TestSetChecksum(t *testing.T) {
 					PseudonodeID: 0,
 				},
 				SequenceNumber: 200,
+				Checksum:       100,
 				TypeBlock:      55,
 				TLVs:           make([]TLV, 0),
 			},
@@ -97,7 +102,7 @@ func TestSetChecksum(t *testing.T) {
 				0, 255,
 				1, 2, 3, 4, 5, 6, 0, 0,
 				0, 0, 0, 200,
-				0x76, 0x17,
+				0, 100,
 				55,
 			},
 		},
@@ -111,6 +116,7 @@ func TestSetChecksum(t *testing.T) {
 					PseudonodeID: 0,
 				},
 				SequenceNumber: 200,
+				Checksum:       100,
 				TypeBlock:      55,
 				TLVs: []TLV{
 					NewPaddingTLV(2),
@@ -121,7 +127,7 @@ func TestSetChecksum(t *testing.T) {
 				0, 255,
 				1, 2, 3, 4, 5, 6, 0, 0,
 				0, 0, 0, 200,
-				0xf8, 0x21,
+				0, 100,
 				55,
 				8, 2,
 				0, 0,
@@ -131,7 +137,6 @@ func TestSetChecksum(t *testing.T) {
 
 	for _, test := range tests {
 		buf := bytes.NewBuffer(nil)
-		test.lspdu.SetChecksum()
 		test.lspdu.Serialize(buf)
 		assert.Equalf(t, test.expected, buf.Bytes(), "Unexpected result in test %q", test.name)
 	}
@@ -169,7 +174,7 @@ func TestDecodeLSPDU(t *testing.T) {
 		{
 			name: "LSP with two TLVs",
 			input: []byte{
-				0, 29, // Length
+				0, 30, // Length
 				0, 200, // Lifetime
 				10, 20, 30, 40, 50, 60, 0, 10, // LSPID
 				0, 0, 1, 0, // Sequence Number
@@ -180,11 +185,12 @@ func TestDecodeLSPDU(t *testing.T) {
 			},
 			wantFail: false,
 			expected: &LSPDU{
-				Length:            29,
+				Length:            30,
 				RemainingLifetime: 200,
 				LSPID: LSPID{
 					SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
-					PseudonodeID: 10,
+					PseudonodeID: 0,
+					LSPNumber:    10,
 				},
 				SequenceNumber: 256,
 				Checksum:       0,
@@ -224,3 +230,73 @@ func TestDecodeLSPDU(t *testing.T) {
 		assert.Equalf(t, test.expected, lspdu, "Test %q", test.name)
 	}
 }
+
+func TestString(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    *LSPID
+		expected string
+	}{
+		{
+			name: "Test #1",
+			input: &LSPID{
+				SystemID:     types.SystemID{1, 2, 3, 4, 5, 6},
+				PseudonodeID: 5,
+				LSPNumber:    7,
+			},
+			expected: "010203.040506.05-07",
+		},
+	}
+
+	for _, test := range tests {
+		res := test.input.String()
+		assert.Equal(t, test.expected, res, test.name)
+	}
+}
+
+func TestSetChecksum(t *testing.T) {
+	tests := []struct {
+		name     string
+		lspdu    *LSPDU
+		expected uint16
+	}{
+		{
+			name: "Test #1",
+			lspdu: &LSPDU{
+				Length:            29,
+				RemainingLifetime: 3591,
+				LSPID: LSPID{
+					SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+					PseudonodeID: 0,
+					LSPNumber:    0,
+				},
+				SequenceNumber: 1,
+				TypeBlock:      3,
+				TLVs: []TLV{
+					&AreaAddressesTLV{
+						TLVType:   AreaAddressesTLVType,
+						TLVLength: 6,
+						AreaIDs: []types.AreaID{
+							{
+								0x49, 0, 1, 0, 16,
+							},
+						},
+					},
+					ProtocolsSupportedTLV{
+						TLVType:   ProtocolsSupportedTLVType,
+						TLVLength: 2,
+						NetworkLayerProtocolIDs: []uint8{
+							0xcc, 0x8e,
+						},
+					},
+				},
+			},
+			expected: 0x35ae,
+		},
+	}
+
+	for _, test := range tests {
+		test.lspdu.SetChecksum()
+		assert.Equal(t, test.expected, test.lspdu.Checksum, test.name)
+	}
+}
diff --git a/protocols/isis/packet/psnp.go b/protocols/isis/packet/psnp.go
index 3b4ac99eca3058207d80a3723ee2703fcd6d9d34..6d25f07379895d30c7f7f27d26ed57bdc64518a2 100644
--- a/protocols/isis/packet/psnp.go
+++ b/protocols/isis/packet/psnp.go
@@ -2,31 +2,31 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 	"math"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	umath "github.com/bio-routing/bio-rd/util/math"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 const (
 	// PSNPMinLen is the minimal length of PSNP PDU
-	PSNPMinLen = 8
+	PSNPMinLen = 17
 )
 
 // PSNP represents a Partial Sequence Number PDU
 type PSNP struct {
 	PDULength  uint16
-	SourceID   types.SystemID
-	LSPEntries []LSPEntry
+	SourceID   types.SourceID
+	LSPEntries []*LSPEntry
 }
 
 // NewPSNPs creates the necessary number of PSNP PDUs to carry all LSPEntries
-func NewPSNPs(sourceID types.SystemID, lspEntries []LSPEntry, maxPDULen int) []PSNP {
+func NewPSNPs(sourceID types.SourceID, lspEntries []*LSPEntry, maxPDULen int) []PSNP {
 	left := len(lspEntries)
-	lspsPerPSNP := (maxPDULen - PSNPMinLen) / LSPEntryLen
+	lspsPerPSNP := (maxPDULen - PSNPMinLen - 2) / LSPEntryLen
 	numPSNPs := int(math.Ceil(float64(left) / float64(lspsPerPSNP)))
 	res := make([]PSNP, numPSNPs)
 
@@ -46,13 +46,13 @@ func NewPSNPs(sourceID types.SystemID, lspEntries []LSPEntry, maxPDULen int) []P
 	return res
 }
 
-func newPSNP(sourceID types.SystemID, lspEntries []LSPEntry) *PSNP {
+func newPSNP(sourceID types.SourceID, lspEntries []*LSPEntry) *PSNP {
 	if len(lspEntries) == 0 {
 		return nil
 	}
 
 	psnp := PSNP{
-		PDULength:  PSNPMinLen + uint16(len(lspEntries))*LSPEntryLen,
+		PDULength:  PSNPMinLen + 2 + uint16(len(lspEntries))*LSPEntryLen,
 		SourceID:   sourceID,
 		LSPEntries: lspEntries,
 	}
@@ -63,11 +63,8 @@ func newPSNP(sourceID types.SystemID, lspEntries []LSPEntry) *PSNP {
 // Serialize serializes PSNPs
 func (c *PSNP) Serialize(buf *bytes.Buffer) {
 	buf.Write(convert.Uint16Byte(c.PDULength))
-	buf.Write(c.SourceID[:])
-
-	for _, lspEntry := range c.LSPEntries {
-		lspEntry.Serialize(buf)
-	}
+	buf.Write(c.SourceID.Serialize())
+	NewLSPEntriesTLV(c.LSPEntries).Serialize(buf)
 }
 
 // DecodePSNP decodes a Partion Sequence Number PDU
@@ -81,17 +78,17 @@ func DecodePSNP(buf *bytes.Buffer) (*PSNP, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	nEntries := (psnp.PDULength - PSNPMinLen) / LSPEntryLen
-	psnp.LSPEntries = make([]LSPEntry, nEntries)
+	psnp.LSPEntries = make([]*LSPEntry, nEntries)
 	for i := uint16(0); i < nEntries; i++ {
 		lspEntry, err := decodeLSPEntry(buf)
 		if err != nil {
-			return nil, errors.Wrap(err, "Unable to get LSPEntries")
+			return nil, fmt.Errorf("Unable to get LSPEntries: %v", err)
 		}
-		psnp.LSPEntries[i] = *lspEntry
+		psnp.LSPEntries[i] = lspEntry
 	}
 
 	return psnp, nil
diff --git a/protocols/isis/packet/psnp_test.go b/protocols/isis/packet/psnp_test.go
index 31c0704c0ddde73655daeb46b1193fdb833c22b5..020032ff5070146efe9978b3ae6fbd61393bade7 100644
--- a/protocols/isis/packet/psnp_test.go
+++ b/protocols/isis/packet/psnp_test.go
@@ -11,15 +11,18 @@ import (
 func TestNewPSNPs(t *testing.T) {
 	tests := []struct {
 		name         string
-		sourceID     types.SystemID
-		lspEntries   []LSPEntry
+		sourceID     types.SourceID
+		lspEntries   []*LSPEntry
 		maxPDULength int
 		expected     []PSNP
 	}{
 		{
-			name:     "All in one packet",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "All in one packet",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1000,
 					RemainingLifetime: 2000,
@@ -33,9 +36,12 @@ func TestNewPSNPs(t *testing.T) {
 			maxPDULength: 1492,
 			expected: []PSNP{
 				{
-					PDULength: 24,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 35,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1000,
 							RemainingLifetime: 2000,
@@ -50,9 +56,12 @@ func TestNewPSNPs(t *testing.T) {
 			},
 		},
 		{
-			name:     "2 packets",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "2 packets",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1001,
 					RemainingLifetime: 2001,
@@ -60,6 +69,7 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 200,
+						LSPNumber:    100,
 					},
 				},
 				{
@@ -69,15 +79,19 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 100,
+						LSPNumber:    200,
 					},
 				},
 			},
-			maxPDULength: 24,
+			maxPDULength: 35,
 			expected: []PSNP{
 				{
-					PDULength: 24,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 35,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1001,
 							RemainingLifetime: 2001,
@@ -85,14 +99,18 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 200,
+								LSPNumber:    100,
 							},
 						},
 					},
 				},
 				{
-					PDULength: 24,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 35,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1000,
 							RemainingLifetime: 2000,
@@ -100,6 +118,7 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 100,
+								LSPNumber:    200,
 							},
 						},
 					},
@@ -107,9 +126,12 @@ func TestNewPSNPs(t *testing.T) {
 			},
 		},
 		{
-			name:     "2 packets with odd length",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "2 packets with odd length",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1001,
 					RemainingLifetime: 2001,
@@ -117,6 +139,7 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 200,
+						LSPNumber:    10,
 					},
 				},
 				{
@@ -126,15 +149,19 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 100,
+						LSPNumber:    20,
 					},
 				},
 			},
-			maxPDULength: 28,
+			maxPDULength: 40,
 			expected: []PSNP{
 				{
-					PDULength: 24,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 35,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1001,
 							RemainingLifetime: 2001,
@@ -142,14 +169,18 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 200,
+								LSPNumber:    10,
 							},
 						},
 					},
 				},
 				{
-					PDULength: 24,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 35,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1000,
 							RemainingLifetime: 2000,
@@ -157,6 +188,7 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 100,
+								LSPNumber:    20,
 							},
 						},
 					},
@@ -164,9 +196,12 @@ func TestNewPSNPs(t *testing.T) {
 			},
 		},
 		{
-			name:     "2 LSPEntries, 1 packet",
-			sourceID: types.SystemID{10, 20, 30, 40, 50, 60},
-			lspEntries: []LSPEntry{
+			name: "2 LSPEntries, 1 packet",
+			sourceID: types.SourceID{
+				SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+				CircuitID: 0,
+			},
+			lspEntries: []*LSPEntry{
 				{
 					SequenceNumber:    1001,
 					RemainingLifetime: 2001,
@@ -174,6 +209,7 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 200,
+						LSPNumber:    10,
 					},
 				},
 				{
@@ -183,15 +219,19 @@ func TestNewPSNPs(t *testing.T) {
 					LSPID: LSPID{
 						SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 						PseudonodeID: 100,
+						LSPNumber:    20,
 					},
 				},
 			},
-			maxPDULength: 40,
+			maxPDULength: 51,
 			expected: []PSNP{
 				{
-					PDULength: 40,
-					SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-					LSPEntries: []LSPEntry{
+					PDULength: 51,
+					SourceID: types.SourceID{
+						SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+						CircuitID: 0,
+					},
+					LSPEntries: []*LSPEntry{
 						{
 							SequenceNumber:    1001,
 							RemainingLifetime: 2001,
@@ -199,6 +239,7 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 200,
+								LSPNumber:    10,
 							},
 						},
 						{
@@ -208,6 +249,7 @@ func TestNewPSNPs(t *testing.T) {
 							LSPID: LSPID{
 								SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
 								PseudonodeID: 100,
+								LSPNumber:    20,
 							},
 						},
 					},
@@ -228,30 +270,67 @@ func TestPSNPSerialize(t *testing.T) {
 		psnp     PSNP
 		expected []byte
 	}{
+		{
+			name: "Test #2",
+			psnp: PSNP{
+				PDULength: 0x23,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{0, 0, 0, 0, 0, 3},
+					CircuitID: 0,
+				},
+				LSPEntries: []*LSPEntry{
+					{
+						SequenceNumber:    0x15,
+						RemainingLifetime: 1196,
+						LSPChecksum:       0xe4ef,
+						LSPID: LSPID{
+							SystemID:     types.SystemID{0, 0, 0, 0, 0, 2},
+							PseudonodeID: 0,
+						},
+					},
+				},
+			},
+			expected: []byte{
+				0x00, 0x23, // Length
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, // SystemID
+				0x09,       // TLV Type
+				0x10,       // TLV Length
+				0x04, 0xac, // Remaining Lifetime
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, //LSPID
+				0x00, 0x00, 0x00, 0x15, // Sequence Number
+				0xe4, 0xef, // // Checksum
+			},
+		},
 		{
 			name: "Test #1",
 			psnp: PSNP{
 				PDULength: 100,
-				SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-				LSPEntries: []LSPEntry{
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
+				LSPEntries: []*LSPEntry{
 					{
-						SequenceNumber:    123,
 						RemainingLifetime: 255,
-						LSPChecksum:       111,
 						LSPID: LSPID{
 							SystemID:     types.SystemID{10, 20, 30, 40, 50, 61},
 							PseudonodeID: 11,
+							LSPNumber:    10,
 						},
+						SequenceNumber: 123,
+						LSPChecksum:    111,
 					},
 				},
 			},
 			expected: []byte{
-				0, 100,
-				10, 20, 30, 40, 50, 60,
-				0, 0, 0, 123,
-				0, 255,
-				0, 111,
-				10, 20, 30, 40, 50, 61, 0, 11,
+				0, 100, // Length
+				10, 20, 30, 40, 50, 60, 0, // SystemID
+				9,      // TLV Type
+				16,     // TLV Length
+				0, 255, // Remaining Lifetime
+				10, 20, 30, 40, 50, 61, 11, 10, // LSPID
+				0, 0, 0, 123, // Sequence Number
+				0, 111, // Checksum
 			},
 		},
 	}
@@ -273,16 +352,16 @@ func TestDecodePSNP(t *testing.T) {
 		{
 			name: "Incomplete PSNP",
 			input: []byte{
-				0, 24, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 33, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 			},
 			wantFail: true,
 		},
 		{
 			name: "Incomplete PSNP LSPEntry",
 			input: []byte{
-				0, 24, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
+				0, 33, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
 				0, 0, 0, 20, // Sequence Number
 			},
 			wantFail: true,
@@ -290,26 +369,33 @@ func TestDecodePSNP(t *testing.T) {
 		{
 			name: "PSNP with one LSPEntry",
 			input: []byte{
-				0, 24, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
-				0, 0, 0, 20, // Sequence Number
+				0, 33, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
+
 				1, 0, // Remaining Lifetime
-				2, 0, // Checksum
 				11, 22, 33, 44, 55, 66, // SystemID
-				0, 20, // Pseudonode ID
+				0,           // Pseudonode ID
+				20,          // LSPNumber
+				0, 0, 0, 20, // Sequence Number
+				2, 0, // Checksum
+
 			},
 			wantFail: false,
 			expected: &PSNP{
-				PDULength: 24,
-				SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-				LSPEntries: []LSPEntry{
+				PDULength: 33,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
+				LSPEntries: []*LSPEntry{
 					{
 						SequenceNumber:    20,
 						RemainingLifetime: 256,
 						LSPChecksum:       512,
 						LSPID: LSPID{
 							SystemID:     types.SystemID{11, 22, 33, 44, 55, 66},
-							PseudonodeID: 20,
+							PseudonodeID: 0,
+							LSPNumber:    20,
 						},
 					},
 				},
@@ -318,24 +404,31 @@ func TestDecodePSNP(t *testing.T) {
 		{
 			name: "PSNP with two LSPEntries",
 			input: []byte{
-				0, 40, // Length
-				10, 20, 30, 40, 50, 60, // Source ID
-				0, 0, 0, 20, // Sequence Number
+				0, 49, // Length
+				10, 20, 30, 40, 50, 60, 0, // Source ID
+
 				1, 0, // Remaining Lifetime
-				2, 0, // Checksum
 				11, 22, 33, 44, 55, 66, // SystemID
-				0, 20, // Pseudonode ID
-				0, 0, 0, 21, // Sequence Number
-				2, 0, // Remaining Lifetime
+				20,          // Pseudonode ID
+				0,           // LSP Number
+				0, 0, 0, 20, // Sequence Number
 				2, 0, // Checksum
+
+				2, 0, // Remaining Lifetime
 				11, 22, 33, 44, 55, 67, // SystemID
-				0, 21, // Pseudonode ID
+				21,          // Pseudonode ID
+				00,          // LSP Number
+				0, 0, 0, 21, // Sequence Number
+				2, 0, // Checksum
 			},
 			wantFail: false,
 			expected: &PSNP{
-				PDULength: 40,
-				SourceID:  types.SystemID{10, 20, 30, 40, 50, 60},
-				LSPEntries: []LSPEntry{
+				PDULength: 49,
+				SourceID: types.SourceID{
+					SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+					CircuitID: 0,
+				},
+				LSPEntries: []*LSPEntry{
 					{
 						SequenceNumber:    20,
 						RemainingLifetime: 256,
diff --git a/protocols/isis/packet/tlv.go b/protocols/isis/packet/tlv.go
index 72064a481f8a317d44b98cc1533f2744b879553e..7a203d53f2350235597ab377ceff6c22fa5f3572 100644
--- a/protocols/isis/packet/tlv.go
+++ b/protocols/isis/packet/tlv.go
@@ -2,6 +2,7 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
 	"github.com/pkg/errors"
@@ -26,6 +27,20 @@ func serializeTLVs(tlvs []TLV) []byte {
 }
 
 func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
+	TLVs := make([]TLV, 0)
+	for buf.Len() > 0 {
+		tlv, err := readTLV(buf)
+		if err != nil {
+			return nil, errors.Wrap(err, "Unable to read TLV")
+		}
+
+		TLVs = append(TLVs, tlv)
+	}
+
+	return TLVs, nil
+}
+
+func readTLV(buf *bytes.Buffer) (TLV, error) {
 	var err error
 	tlvType := uint8(0)
 	tlvLength := uint8(0)
@@ -35,44 +50,36 @@ func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
 		&tlvLength,
 	}
 
-	TLVs := make([]TLV, 0)
-
-	length := buf.Len()
-	read := uint16(0)
-	for read < uint16(length) {
-		err = decode.Decode(buf, headFields)
-		if err != nil {
-			return nil, errors.Wrap(err, "Unable to decode fields")
-		}
-
-		read += 2
-		read += uint16(tlvLength)
+	err = decode.Decode(buf, headFields)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+	}
 
-		var tlv TLV
-		switch tlvType {
-		case DynamicHostNameTLVType:
-			tlv, err = readDynamicHostnameTLV(buf, tlvType, tlvLength)
-		case ChecksumTLVType:
-			tlv, err = readChecksumTLV(buf, tlvType, tlvLength)
-		case ProtocolsSupportedTLVType:
-			tlv, err = readProtocolsSupportedTLV(buf, tlvType, tlvLength)
-		case IPInterfaceAddressTLVType:
-			tlv, err = readIPInterfaceAddressTLV(buf, tlvType, tlvLength)
-		case AreaAddressesTLVType:
-			tlv, err = readAreaAddressesTLV(buf, tlvType, tlvLength)
-		case P2PAdjacencyStateTLVType:
-			tlv, err = readP2PAdjacencyStateTLV(buf, tlvType, tlvLength)
-		case ISNeighborsTLVType:
-			tlv, err = readISNeighborsTLV(buf, tlvType, tlvLength)
-		default:
-			tlv, err = readUnknownTLV(buf, tlvType, tlvLength)
-		}
+	var tlv TLV
+	switch tlvType {
+	case DynamicHostNameTLVType:
+		tlv, err = readDynamicHostnameTLV(buf, tlvType, tlvLength)
+	case ChecksumTLVType:
+		tlv, err = readChecksumTLV(buf, tlvType, tlvLength)
+	case ProtocolsSupportedTLVType:
+		tlv, err = readProtocolsSupportedTLV(buf, tlvType, tlvLength)
+	case IPInterfaceAddressesTLVType:
+		tlv, err = readIPInterfaceAddressesTLV(buf, tlvType, tlvLength)
+	case AreaAddressesTLVType:
+		tlv, err = readAreaAddressesTLV(buf, tlvType, tlvLength)
+	case P2PAdjacencyStateTLVType:
+		tlv, err = readP2PAdjacencyStateTLV(buf, tlvType, tlvLength)
+	case ISNeighborsTLVType:
+		tlv, err = readISNeighborsTLV(buf, tlvType, tlvLength)
+	case LSPEntriesTLVType:
+		tlv, err = readLSPEntriesTLV(buf, tlvType, tlvLength)
+	default:
+		tlv, err = readUnknownTLV(buf, tlvType, tlvLength)
+	}
 
-		if err != nil {
-			return nil, errors.Wrap(err, "Unable to read TLV")
-		}
-		TLVs = append(TLVs, tlv)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to read TLV: %v", err)
 	}
 
-	return TLVs, nil
+	return tlv, nil
 }
diff --git a/protocols/isis/packet/tlv_area_addresses.go b/protocols/isis/packet/tlv_area_addresses.go
index 35ba0d792ffc92e5c1098c8ca61c3e2990b1ff34..cb3ff01815bf970860e3b383b758ba380dcbd0e4 100644
--- a/protocols/isis/packet/tlv_area_addresses.go
+++ b/protocols/isis/packet/tlv_area_addresses.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
-	"github.com/pkg/errors"
 )
 
 // AreaAddressesTLVType is the type value of an area address TLV
@@ -29,14 +29,14 @@ func readAreaAddressesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*A
 	for read < tlvLength {
 		areaLen, err := buf.ReadByte()
 		if err != nil {
-			return nil, errors.Wrap(err, "Unable to read")
+			return nil, fmt.Errorf("Unable to read: %v", err)
 		}
 		read++
 
 		newArea := make(types.AreaID, areaLen)
 		_, err = buf.Read(newArea)
 		if err != nil {
-			return nil, errors.Wrap(err, "Unable to read")
+			return nil, fmt.Errorf("Unable to read: %v", err)
 		}
 		read += areaLen
 
@@ -50,13 +50,12 @@ func readAreaAddressesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*A
 // NewAreaAddressesTLV creates a new area addresses TLV
 func NewAreaAddressesTLV(areas []types.AreaID) *AreaAddressesTLV {
 	a := &AreaAddressesTLV{
-		TLVType:   AreaAddressesTLVType,
-		TLVLength: 0,
-		AreaIDs:   make([]types.AreaID, len(areas)),
+		TLVType: AreaAddressesTLVType,
+		AreaIDs: make([]types.AreaID, len(areas)),
 	}
 
 	for i, area := range areas {
-		a.TLVLength += uint8(len(area)) + 1
+		a.TLVLength += uint8(len(areas[i])) + 1
 		a.AreaIDs[i] = area
 	}
 
@@ -64,22 +63,22 @@ func NewAreaAddressesTLV(areas []types.AreaID) *AreaAddressesTLV {
 }
 
 // Type gets the type of the TLV
-func (a AreaAddressesTLV) Type() uint8 {
+func (a *AreaAddressesTLV) Type() uint8 {
 	return a.TLVType
 }
 
 // Length gets the length of the TLV
-func (a AreaAddressesTLV) Length() uint8 {
+func (a *AreaAddressesTLV) Length() uint8 {
 	return a.TLVLength
 }
 
 // Value gets the TLV itself
-func (a AreaAddressesTLV) Value() interface{} {
+func (a *AreaAddressesTLV) Value() interface{} {
 	return a
 }
 
 // Serialize serializes an area address TLV
-func (a AreaAddressesTLV) Serialize(buf *bytes.Buffer) {
+func (a *AreaAddressesTLV) Serialize(buf *bytes.Buffer) {
 	buf.WriteByte(a.TLVType)
 	buf.WriteByte(a.TLVLength)
 
diff --git a/protocols/isis/packet/tlv_area_addresses_test.go b/protocols/isis/packet/tlv_area_addresses_test.go
index 72a93315732c9261750509e3aedaf62247e5586d..0962b4213faaa80253ad3031da3a582ceddd9f83 100644
--- a/protocols/isis/packet/tlv_area_addresses_test.go
+++ b/protocols/isis/packet/tlv_area_addresses_test.go
@@ -100,18 +100,6 @@ func TestNewAreaAddressesTLV(t *testing.T) {
 	}
 }
 
-func TestAreaAddressesTLV(t *testing.T) {
-	tlv := NewAreaAddressesTLV([]types.AreaID{})
-
-	assert.Equal(t, uint8(1), tlv.Type())
-	assert.Equal(t, uint8(0), tlv.Length())
-	assert.Equal(t, AreaAddressesTLV{
-		TLVType:   1,
-		TLVLength: 0,
-		AreaIDs:   []types.AreaID{},
-	}, tlv.Value())
-}
-
 func TestAreaAddressesTLVSerialize(t *testing.T) {
 	tests := []struct {
 		name     string
@@ -119,7 +107,7 @@ func TestAreaAddressesTLVSerialize(t *testing.T) {
 		expected []byte
 	}{
 		{
-			name: "Full",
+			name: "Empty",
 			input: &AreaAddressesTLV{
 				TLVType:   1,
 				TLVLength: 0,
@@ -130,7 +118,7 @@ func TestAreaAddressesTLVSerialize(t *testing.T) {
 		{
 			name: "Full",
 			input: &AreaAddressesTLV{
-				TLVType:   8,
+				TLVType:   1,
 				TLVLength: 4,
 				AreaIDs: []types.AreaID{
 					{
@@ -138,7 +126,20 @@ func TestAreaAddressesTLVSerialize(t *testing.T) {
 					},
 				},
 			},
-			expected: []byte{8, 4, 3, 1, 2, 3},
+			expected: []byte{1, 4, 3, 1, 2, 3},
+		},
+		{
+			name: "Real Example",
+			input: &AreaAddressesTLV{
+				TLVType:   1,
+				TLVLength: 7,
+				AreaIDs: []types.AreaID{
+					{
+						0, 4, 0, 1, 0, 16,
+					},
+				},
+			},
+			expected: []byte{1, 7, 6, 0, 4, 0, 1, 0, 16},
 		},
 	}
 
@@ -149,3 +150,28 @@ func TestAreaAddressesTLVSerialize(t *testing.T) {
 		assert.Equalf(t, test.expected, buf.Bytes(), "Test %q", test.name)
 	}
 }
+
+func TestAreaAddressesTLVType(t *testing.T) {
+	tlv := &AreaAddressesTLV{
+		TLVType: 100,
+	}
+
+	assert.Equal(t, uint8(100), tlv.Type())
+}
+
+func TestAreaAddressesTLVLength(t *testing.T) {
+	tlv := &AreaAddressesTLV{
+		TLVLength: 123,
+	}
+
+	assert.Equal(t, uint8(123), tlv.Length())
+}
+
+func TestAreaAddressesTLVValue(t *testing.T) {
+	tlv := &AreaAddressesTLV{
+		TLVLength: 123,
+		AreaIDs:   []types.AreaID{},
+	}
+
+	assert.Equal(t, tlv, tlv.Value())
+}
diff --git a/protocols/isis/packet/tlv_checksum.go b/protocols/isis/packet/tlv_checksum.go
index 00174f5767f9db447970d4c472d3a9fb71310ccb..3dfb509849874ba3beebb66c182c3706041f5983 100644
--- a/protocols/isis/packet/tlv_checksum.go
+++ b/protocols/isis/packet/tlv_checksum.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 // ChecksumTLVType is the type value of a checksum TLV
@@ -45,7 +45,7 @@ func readChecksumTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Checks
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_dynamic_hostname.go b/protocols/isis/packet/tlv_dynamic_hostname.go
index 39a2a80bd86aa0090d81285a5dc0ed87eba979ff..1a2b74977718b3e9c99fc0bd6677956897b89bd6 100644
--- a/protocols/isis/packet/tlv_dynamic_hostname.go
+++ b/protocols/isis/packet/tlv_dynamic_hostname.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
-	"github.com/pkg/errors"
 )
 
 // DynamicHostNameTLVType is the type value of dynamic hostname TLV
@@ -32,6 +32,15 @@ func (d *DynamicHostNameTLV) Value() interface{} {
 	return d
 }
 
+// NewDynamicHostnameTLV creates a new dynamic hostname TLV
+func NewDynamicHostnameTLV(name []byte) *DynamicHostNameTLV {
+	return &DynamicHostNameTLV{
+		TLVType:   DynamicHostNameTLVType,
+		TLVLength: uint8(len(name)),
+		Hostname:  name,
+	}
+}
+
 func readDynamicHostnameTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*DynamicHostNameTLV, error) {
 	pdu := &DynamicHostNameTLV{
 		TLVType:   tlvType,
@@ -45,7 +54,7 @@ func readDynamicHostnameTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_dynamic_hostname_test.go b/protocols/isis/packet/tlv_dynamic_hostname_test.go
index cee8d43d08431e9a7b0d4e148eeebd167cd33129..bc921644fce6ac5b0cf2d116208b34df6dea2294 100644
--- a/protocols/isis/packet/tlv_dynamic_hostname_test.go
+++ b/protocols/isis/packet/tlv_dynamic_hostname_test.go
@@ -82,3 +82,39 @@ func TestReadDynamicHostnameTLV(t *testing.T) {
 		assert.Equalf(t, test.expected, tlv, "Test %q", test.name)
 	}
 }
+
+func TestNewDynamicHostnameTLV(t *testing.T) {
+	tlv := NewDynamicHostnameTLV([]byte("abcd"))
+
+	expected := &DynamicHostNameTLV{
+		TLVType:   137,
+		TLVLength: 4,
+		Hostname:  []byte("abcd"),
+	}
+
+	assert.Equal(t, expected, tlv)
+}
+
+func TestDynamicHostnameTLVType(t *testing.T) {
+	tlv := &DynamicHostNameTLV{
+		TLVType: 100,
+	}
+
+	assert.Equal(t, uint8(100), tlv.Type())
+}
+
+func TestDynamicHostnameTLVLength(t *testing.T) {
+	tlv := &DynamicHostNameTLV{
+		TLVLength: 123,
+	}
+
+	assert.Equal(t, uint8(123), tlv.Length())
+}
+
+func TestDynamicHostnameTLVValue(t *testing.T) {
+	tlv := &DynamicHostNameTLV{
+		TLVLength: 123,
+	}
+
+	assert.Equal(t, tlv, tlv.Value())
+}
diff --git a/protocols/isis/packet/tlv_extended_ip_reachability.go b/protocols/isis/packet/tlv_extended_ip_reachability.go
index 9fbbe5c007eeea7d156bd19ad69b1670f6e61975..4da8ecb937499196037e73874fa1ad9bb0fdae55 100644
--- a/protocols/isis/packet/tlv_extended_ip_reachability.go
+++ b/protocols/isis/packet/tlv_extended_ip_reachability.go
@@ -1,14 +1,141 @@
 package packet
 
-const ExtendedIPReachabilityTLVType = 135
+import (
+	"bytes"
+	"fmt"
 
+	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/bio-routing/tflow2/convert"
+	"github.com/pkg/errors"
+)
+
+const (
+	// ExtendedIPReachabilityTLVType is the type value of an Extended IP Reachability TLV
+	ExtendedIPReachabilityTLVType = 135
+
+	// ExtendedIPReachabilityLength is the length of an Extended IP Reachability excluding Sub TLVs
+	ExtendedIPReachabilityLength = 9
+)
+
+// ExtendedIPReachabilityTLV is an Extended IP Reachability TLV
 type ExtendedIPReachabilityTLV struct {
-	TLVType        uint8
-	TLVLength      uint8
+	TLVType                  uint8
+	TLVLength                uint8
+	ExtendedIPReachabilities []*ExtendedIPReachability
+}
+
+// Type gets the type of the TLV
+func (e *ExtendedIPReachabilityTLV) Type() uint8 {
+	return e.TLVType
+}
+
+// Length gets the length of the TLV
+func (e *ExtendedIPReachabilityTLV) Length() uint8 {
+	return e.TLVLength
+}
+
+// Value returns the TLV itself
+func (e *ExtendedIPReachabilityTLV) Value() interface{} {
+	return e
+}
+
+// Serialize serializes an ExtendedIPReachabilityTLV
+func (e *ExtendedIPReachabilityTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(e.TLVType)
+	buf.WriteByte(e.TLVLength)
+
+	for i := range e.ExtendedIPReachabilities {
+		e.ExtendedIPReachabilities[i].Serialize(buf)
+	}
+}
+
+// NewExtendedIPReachabilityTLV creates a new ExtendedIPReachabilityTLV
+func NewExtendedIPReachabilityTLV() *ExtendedIPReachabilityTLV {
+	return &ExtendedIPReachabilityTLV{
+		TLVType:                  ExtendedIPReachabilityTLVType,
+		TLVLength:                0,
+		ExtendedIPReachabilities: make([]*ExtendedIPReachability, 0),
+	}
+}
+
+func readExtendedIPReachabilityTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*ExtendedIPReachabilityTLV, error) {
+	pdu := NewExtendedIPReachabilityTLV()
+	pdu.TLVLength = tlvLength
+
+	toRead := tlvLength
+	for toRead > 0 {
+		extIPReach, err := readExtendedIPReachability(buf)
+		if err != nil {
+			return nil, errors.Wrap(err, "Unable to reach extended IP reachability")
+		}
+
+		toRead -= ExtendedIPReachabilityLength
+		for i := range extIPReach.SubTLVs {
+			toRead -= extIPReach.SubTLVs[i].Length()
+		}
+
+		pdu.ExtendedIPReachabilities = append(pdu.ExtendedIPReachabilities, extIPReach)
+	}
+
+	return pdu, nil
+}
+
+// ExtendedIPReachability is the Extended IP Reachability Part of an ExtendedIPReachabilityTLV
+type ExtendedIPReachability struct {
 	Metric         uint32
 	UDSubBitPfxLen uint8
 	Address        uint32
-	SubTLVType     uint8
-	SubTLVLength   uint8
-	SubTLVs        []interface{}
+	SubTLVs        []TLV
+}
+
+// Serialize serializes an ExtendedIPReachability
+func (e *ExtendedIPReachability) Serialize(buf *bytes.Buffer) {
+	buf.Write(convert.Uint32Byte(e.Metric))
+	buf.WriteByte(e.UDSubBitPfxLen)
+	buf.Write(convert.Uint32Byte(e.Address))
+
+	for i := range e.SubTLVs {
+		e.SubTLVs[i].Serialize(buf)
+	}
+}
+
+func (e *ExtendedIPReachability) hasSubTLVs() bool {
+	return e.UDSubBitPfxLen&(uint8(1)<<6) == 64
+}
+
+// PfxLen returns the prefix length
+func (e *ExtendedIPReachability) PfxLen() uint8 {
+	return (e.UDSubBitPfxLen << 2) >> 2
+}
+
+func readExtendedIPReachability(buf *bytes.Buffer) (*ExtendedIPReachability, error) {
+	e := &ExtendedIPReachability{}
+
+	fields := []interface{}{
+		&e.Metric,
+		&e.UDSubBitPfxLen,
+		&e.Address,
+	}
+
+	err := decode.Decode(buf, fields)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+	}
+
+	if !e.hasSubTLVs() {
+		return e, nil
+	}
+
+	subTLVsLen := uint8(0)
+	err = decode.Decode(buf, []interface{}{&subTLVsLen})
+	if err != nil {
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+	}
+
+	toRead := subTLVsLen
+	for toRead > 0 {
+		// TODO: Read Sub TLVs
+	}
+
+	return e, nil
 }
diff --git a/protocols/isis/packet/tlv_extended_ip_reachability_test.go b/protocols/isis/packet/tlv_extended_ip_reachability_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..91c89cb23ee57a977671805118086b1d7e62fd92
--- /dev/null
+++ b/protocols/isis/packet/tlv_extended_ip_reachability_test.go
@@ -0,0 +1,128 @@
+package packet
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPfxLen(t *testing.T) {
+	tests := []struct {
+		name     string
+		e        *ExtendedIPReachability
+		expected uint8
+	}{
+		{
+			name: "Test #1",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 32,
+			},
+			expected: 32,
+		},
+		{
+			name: "Test #2",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 96,
+			},
+			expected: 32,
+		},
+		{
+			name: "Test #3",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 24,
+			},
+			expected: 24,
+		},
+	}
+
+	for _, test := range tests {
+		res := test.e.PfxLen()
+		assert.Equal(t, test.expected, res, test.name)
+	}
+}
+
+func TestHasSubTLVs(t *testing.T) {
+	tests := []struct {
+		name     string
+		e        *ExtendedIPReachability
+		expected bool
+	}{
+		{
+			name: "Test #1",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 64,
+			},
+			expected: true,
+		},
+		{
+			name: "Test #2",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 23,
+			},
+			expected: false,
+		},
+		{
+			name: "Test #3",
+			e: &ExtendedIPReachability{
+				UDSubBitPfxLen: 88, // /24 with Sub TLVs (+64)
+			},
+			expected: true,
+		},
+	}
+
+	for _, test := range tests {
+		res := test.e.hasSubTLVs()
+		assert.Equal(t, test.expected, res, test.name)
+	}
+}
+
+func TestReadExtendedIPReachabilityTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    []byte
+		wantFail bool
+		expected *ExtendedIPReachabilityTLV
+	}{
+		{
+			name: "Single entry. No sub TLVs.",
+			input: []byte{
+				// First Extended IP Reach.
+				0, 0, 0, 100, // Metric
+				24,             // UDSubBitPfxLen (no sub TLVs)
+				10, 20, 30, 40, // Address
+			},
+			expected: &ExtendedIPReachabilityTLV{
+				TLVType:   135,
+				TLVLength: 9,
+				ExtendedIPReachabilities: []*ExtendedIPReachability{
+					{
+						Metric:         100,
+						UDSubBitPfxLen: 24,
+						Address:        169090600,
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(test.input)
+		tlv, err := readExtendedIPReachabilityTLV(buf, 135, uint8(len(test.input)))
+		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, tlv, test.name)
+	}
+}
diff --git a/protocols/isis/packet/tlv_extended_is_reachability.go b/protocols/isis/packet/tlv_extended_is_reachability.go
index 20e77188a21fcee35f72427629ac78d4f27e42f5..01bccd246238bda773865dd717a73e95d1c3d70d 100644
--- a/protocols/isis/packet/tlv_extended_is_reachability.go
+++ b/protocols/isis/packet/tlv_extended_is_reachability.go
@@ -1,12 +1,185 @@
 package packet
 
-const ExtendedISReachabilityType = 22
+import (
+	"bytes"
 
+	"github.com/bio-routing/bio-rd/protocols/isis/types"
+	"github.com/bio-routing/tflow2/convert"
+)
+
+const (
+	// ExtendedISReachabilityType is the type value of an Extended IS Reachability TLV
+	ExtendedISReachabilityType = 22
+
+	// LinkLocalRemoteIdentifiersSubTLVType is the type value of an Link Local/Remote Indentifiers Sub TLV
+	LinkLocalRemoteIdentifiersSubTLVType = 4
+
+	// IPv4InterfaceAddressSubTLVType is the type value of an IPv4 interface address sub TLV
+	IPv4InterfaceAddressSubTLVType = 6
+
+	// IPv4NeighborAddressSubTLVType is the type value of an IPv4 neighbor address sub TLV
+	IPv4NeighborAddressSubTLVType = 8
+)
+
+// ExtendedISReachabilityTLV is an Extended IS Reachability TLV
 type ExtendedISReachabilityTLV struct {
-	TLVType      uint8
-	TLVLength    uint8
-	SystemID     [7]byte
-	WideMetrics  [3]byte
+	TLVType   uint8
+	TLVLength uint8
+	Neighbors []*ExtendedISReachabilityNeighbor
+}
+
+// Type gets the type of the TLV
+func (e *ExtendedISReachabilityTLV) Type() uint8 {
+	return e.TLVType
+}
+
+// Length gets the length of the TLV
+func (e *ExtendedISReachabilityTLV) Length() uint8 {
+	return e.TLVLength
+}
+
+// Value returns the TLV itself
+func (e *ExtendedISReachabilityTLV) Value() interface{} {
+	return e
+}
+
+// Serialize serializes an ExtendedISReachabilityTLV
+func (e *ExtendedISReachabilityTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(e.TLVType)
+	buf.WriteByte(e.TLVLength)
+	for i := range e.Neighbors {
+		e.Neighbors[i].Serialize(buf)
+	}
+}
+
+// ExtendedISReachabilityNeighbor is an extended IS Reachability Neighbor
+type ExtendedISReachabilityNeighbor struct {
+	NeighborID   types.SourceID
+	Metric       [3]byte
 	SubTLVLength uint8
-	SubTLVs      []interface{}
+	SubTLVs      []TLV
+}
+
+// Serialize serializes an ExtendedISReachabilityNeighbor
+func (e *ExtendedISReachabilityNeighbor) Serialize(buf *bytes.Buffer) {
+	buf.Write(e.NeighborID.Serialize())
+	buf.Write(e.Metric[:])
+	buf.WriteByte(e.SubTLVLength)
+	for i := range e.SubTLVs {
+		e.SubTLVs[i].Serialize(buf)
+	}
+}
+
+// NewExtendedISReachabilityNeighbor creates a new ExtendedISReachabilityNeighbor
+func NewExtendedISReachabilityNeighbor(neighborID types.SourceID, metric [3]byte) *ExtendedISReachabilityNeighbor {
+	return &ExtendedISReachabilityNeighbor{
+		NeighborID: neighborID,
+		Metric:     metric,
+		SubTLVs:    make([]TLV, 0),
+	}
+}
+
+// NewExtendedISReachabilityTLV creates a new Extended IS Reachability TLV
+func NewExtendedISReachabilityTLV() *ExtendedISReachabilityTLV {
+	e := &ExtendedISReachabilityTLV{
+		TLVType: ExtendedISReachabilityType,
+	}
+
+	return e
+}
+
+// AddSubTLV adds a sub TLV to the ExtendedISReachabilityNeighbor
+func (e *ExtendedISReachabilityNeighbor) AddSubTLV(tlv TLV) {
+	e.SubTLVLength += tlv.Length() + 2
+	e.SubTLVs = append(e.SubTLVs, tlv)
+}
+
+// LinkLocalRemoteIdentifiersSubTLV is an Link Local/Remote Identifiers Sub TLV
+type LinkLocalRemoteIdentifiersSubTLV struct {
+	TLVType   uint8
+	TLVLength uint8
+	Local     uint32
+	Remote    uint32
+}
+
+// Type gets the type of the TLV
+func (l *LinkLocalRemoteIdentifiersSubTLV) Type() uint8 {
+	return l.TLVType
+}
+
+// Length gets the length of the TLV
+func (l *LinkLocalRemoteIdentifiersSubTLV) Length() uint8 {
+	return l.TLVLength
+}
+
+// Value returns the TLV itself
+func (l *LinkLocalRemoteIdentifiersSubTLV) Value() interface{} {
+	return l
+}
+
+// Serialize serializes an IPv4 address sub TLV
+func (l *LinkLocalRemoteIdentifiersSubTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(l.TLVType)
+	buf.WriteByte(l.TLVLength)
+	buf.Write(convert.Uint32Byte(l.Local))
+	buf.Write(convert.Uint32Byte(l.Remote))
+}
+
+// NewLinkLocalRemoteIdentifiersSubTLV creates a new LinkLocalRemoteIdentifiersSubTLV
+func NewLinkLocalRemoteIdentifiersSubTLV(local uint32, remote uint32) *LinkLocalRemoteIdentifiersSubTLV {
+	return &LinkLocalRemoteIdentifiersSubTLV{
+		TLVType:   LinkLocalRemoteIdentifiersSubTLVType,
+		TLVLength: 8,
+		Local:     local,
+		Remote:    remote,
+	}
+}
+
+// IPv4AddressSubTLV is an IPv4 Address Sub TLV (used for both interface and neighbor)
+type IPv4AddressSubTLV struct {
+	TLVType   uint8
+	TLVLength uint8
+	Address   uint32
+}
+
+// Type gets the type of the TLV
+func (s *IPv4AddressSubTLV) Type() uint8 {
+	return s.TLVType
+}
+
+// Length gets the length of the TLV
+func (s *IPv4AddressSubTLV) Length() uint8 {
+	return s.TLVLength
+}
+
+// Value returns the TLV itself
+func (s *IPv4AddressSubTLV) Value() interface{} {
+	return s
+}
+
+// Serialize serializes an IPv4 address sub TLV
+func (s *IPv4AddressSubTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(s.TLVType)
+	buf.WriteByte(s.TLVLength)
+	buf.Write(convert.Uint32Byte(s.Address))
+}
+
+// NewIPv4InterfaceAddressSubTLV creates a new IPv4 Interface Address Sub TLV
+func NewIPv4InterfaceAddressSubTLV(addr uint32) *IPv4AddressSubTLV {
+	return newIPv4AddressSubTLV(IPv4InterfaceAddressSubTLVType, addr)
+}
+
+// NewIPv4NeighborAddressSubTLV creates a new IPv4 Neighbor Address Sub TLV
+func NewIPv4NeighborAddressSubTLV(addr uint32) *IPv4AddressSubTLV {
+	return newIPv4AddressSubTLV(IPv4NeighborAddressSubTLVType, addr)
+}
+
+func newIPv4AddressSubTLV(tlvType uint8, addr uint32) *IPv4AddressSubTLV {
+	tlv := &IPv4AddressSubTLV{
+		TLVType:   tlvType,
+		TLVLength: 4,
+		Address:   addr,
+	}
+
+	return tlv
 }
diff --git a/protocols/isis/packet/tlv_extended_is_reachability_test.go b/protocols/isis/packet/tlv_extended_is_reachability_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..ce6b754cfcda39d05848c89c6f4b4f21d57abcac
--- /dev/null
+++ b/protocols/isis/packet/tlv_extended_is_reachability_test.go
@@ -0,0 +1,144 @@
+package packet
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/bio-routing/bio-rd/protocols/isis/types"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestExtendedISReachabilityTLVSerialize(t *testing.T) {
+	tests := []struct {
+		name     string
+		tlv      *ExtendedISReachabilityTLV
+		expected []byte
+	}{
+		{
+			name: "Test #1",
+			tlv: &ExtendedISReachabilityTLV{
+				TLVType:   22,
+				TLVLength: 21,
+				Neighbors: []*ExtendedISReachabilityNeighbor{
+					{
+						NeighborID: types.SourceID{
+							SystemID:  types.SystemID{10, 20, 30, 40, 50, 60},
+							CircuitID: 100,
+						},
+						Metric:       [3]byte{0, 0, 123},
+						SubTLVLength: 8,
+						SubTLVs: []TLV{
+							NewLinkLocalRemoteIdentifiersSubTLV(1000, 2000),
+						},
+					},
+				},
+			},
+			expected: []byte{
+				22,
+				21,
+				10, 20, 30, 40, 50, 60,
+				100,
+				0, 0, 123,
+				8,
+				4,
+				8,
+				0, 0, 0x3, 0xe8,
+				0, 0, 0x7, 0xd0,
+			},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		test.tlv.Serialize(buf)
+		assert.Equal(t, test.expected, buf.Bytes(), test.name)
+	}
+}
+
+func TestExtendedISReachabilityNeighborAddSubTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		neighbor *ExtendedISReachabilityNeighbor
+		addTLV   TLV
+		expected *ExtendedISReachabilityNeighbor
+	}{
+		{
+			name: "Test #1",
+			neighbor: NewExtendedISReachabilityNeighbor(types.NewSourceID(
+				types.SystemID{1, 2, 3, 4, 5, 6},
+				0,
+			), [3]byte{1, 2, 3}),
+			addTLV: &IPv4AddressSubTLV{
+				TLVType:   6,
+				TLVLength: 4,
+				Address:   111,
+			},
+			expected: &ExtendedISReachabilityNeighbor{
+				NeighborID: types.NewSourceID(
+					types.SystemID{1, 2, 3, 4, 5, 6},
+					0,
+				),
+				Metric:       [3]byte{1, 2, 3},
+				SubTLVLength: 6,
+				SubTLVs: []TLV{
+					&IPv4AddressSubTLV{
+						TLVType:   6,
+						TLVLength: 4,
+						Address:   111,
+					},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		test.neighbor.AddSubTLV(test.addTLV)
+		assert.Equal(t, test.expected, test.neighbor, test.name)
+	}
+}
+
+func TestIPv4AddressSubTLVSerialize(t *testing.T) {
+	tests := []struct {
+		name     string
+		tlv      *IPv4AddressSubTLV
+		expected []byte
+	}{
+		{
+			name: "Test #1",
+			tlv: &IPv4AddressSubTLV{
+				TLVType:   IPv4InterfaceAddressSubTLVType,
+				TLVLength: 4,
+				Address:   111,
+			},
+			expected: []byte{6, 4, 0, 0, 0, 111},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		test.tlv.Serialize(buf)
+		assert.Equal(t, test.expected, buf.Bytes(), test.name)
+	}
+}
+
+func TestNewIPv4InterfaceAddressSubTLV(t *testing.T) {
+	tlv := NewIPv4InterfaceAddressSubTLV(111)
+	expectred := &IPv4AddressSubTLV{
+		TLVType:   6,
+		TLVLength: 4,
+		Address:   111,
+	}
+
+	assert.Equal(t, expectred, tlv)
+}
+
+func TestNewIPv4NeighborAddressSubTLV(t *testing.T) {
+	tlv := NewIPv4NeighborAddressSubTLV(111)
+	expectred := &IPv4AddressSubTLV{
+		TLVType:   8,
+		TLVLength: 4,
+		Address:   111,
+	}
+
+	assert.Equal(t, expectred, tlv)
+}
diff --git a/protocols/isis/packet/tlv_ip_interface_address.go b/protocols/isis/packet/tlv_ip_interface_address.go
deleted file mode 100644
index 85a24f016bef71ca8099347a94078216c1f41aab..0000000000000000000000000000000000000000
--- a/protocols/isis/packet/tlv_ip_interface_address.go
+++ /dev/null
@@ -1,68 +0,0 @@
-package packet
-
-import (
-	"bytes"
-
-	"github.com/bio-routing/bio-rd/util/decode"
-	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
-)
-
-// IPInterfaceAddressTLVType is the type value of an IP interface address TLV
-const IPInterfaceAddressTLVType = 132
-
-// IPInterfaceAddressTLV represents an IP interface TLV
-type IPInterfaceAddressTLV struct {
-	TLVType     uint8
-	TLVLength   uint8
-	IPv4Address uint32
-}
-
-// NewIPInterfaceAddressTLV creates a new IPInterfaceAddressTLV
-func NewIPInterfaceAddressTLV(addr uint32) *IPInterfaceAddressTLV {
-	return &IPInterfaceAddressTLV{
-		TLVType:     IPInterfaceAddressTLVType,
-		TLVLength:   4,
-		IPv4Address: addr,
-	}
-}
-
-func readIPInterfaceAddressTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*IPInterfaceAddressTLV, error) {
-	pdu := &IPInterfaceAddressTLV{
-		TLVType:   tlvType,
-		TLVLength: tlvLength,
-	}
-
-	fields := []interface{}{
-		&pdu.IPv4Address,
-	}
-
-	err := decode.Decode(buf, fields)
-	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
-	}
-
-	return pdu, nil
-}
-
-// Type returns the type of the TLV
-func (i IPInterfaceAddressTLV) Type() uint8 {
-	return i.TLVType
-}
-
-// Length returns the length of the TLV
-func (i IPInterfaceAddressTLV) Length() uint8 {
-	return i.TLVLength
-}
-
-// Value gets the TLV itself
-func (i IPInterfaceAddressTLV) Value() interface{} {
-	return i
-}
-
-// Serialize serializes an IP interfaces address TLV
-func (i IPInterfaceAddressTLV) Serialize(buf *bytes.Buffer) {
-	buf.WriteByte(i.TLVType)
-	buf.WriteByte(i.TLVLength)
-	buf.Write(convert.Uint32Byte(i.IPv4Address))
-}
diff --git a/protocols/isis/packet/tlv_ip_interface_addresses.go b/protocols/isis/packet/tlv_ip_interface_addresses.go
new file mode 100644
index 0000000000000000000000000000000000000000..cabe7b4312ba8d8b1171c8bdcc5b632e01f50c7c
--- /dev/null
+++ b/protocols/isis/packet/tlv_ip_interface_addresses.go
@@ -0,0 +1,72 @@
+package packet
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/bio-routing/tflow2/convert"
+)
+
+// IPInterfaceAddressesTLVType is the type value of an IP interface address TLV
+const IPInterfaceAddressesTLVType = 132
+
+// IPInterfaceAddressesTLV represents an IP interface TLV
+type IPInterfaceAddressesTLV struct {
+	TLVType       uint8
+	TLVLength     uint8
+	IPv4Addresses []uint32
+}
+
+// NewIPInterfaceAddressesTLV creates a new IPInterfaceAddressesTLV
+func NewIPInterfaceAddressesTLV(addrs []uint32) *IPInterfaceAddressesTLV {
+	return &IPInterfaceAddressesTLV{
+		TLVType:       IPInterfaceAddressesTLVType,
+		TLVLength:     4,
+		IPv4Addresses: addrs,
+	}
+}
+
+func readIPInterfaceAddressesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*IPInterfaceAddressesTLV, error) {
+	pdu := &IPInterfaceAddressesTLV{
+		TLVType:       tlvType,
+		TLVLength:     tlvLength,
+		IPv4Addresses: make([]uint32, tlvLength/4),
+	}
+
+	fields := make([]interface{}, len(pdu.IPv4Addresses))
+	for i := range pdu.IPv4Addresses {
+		fields[i] = &pdu.IPv4Addresses[i]
+	}
+
+	err := decode.Decode(buf, fields)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+	}
+
+	return pdu, nil
+}
+
+// Type returns the type of the TLV
+func (i IPInterfaceAddressesTLV) Type() uint8 {
+	return i.TLVType
+}
+
+// Length returns the length of the TLV
+func (i IPInterfaceAddressesTLV) Length() uint8 {
+	return i.TLVLength
+}
+
+// Value gets the TLV itself
+func (i IPInterfaceAddressesTLV) Value() interface{} {
+	return i
+}
+
+// Serialize serializes an IP interfaces address TLV
+func (i IPInterfaceAddressesTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(i.TLVType)
+	buf.WriteByte(i.TLVLength)
+	for j := range i.IPv4Addresses {
+		buf.Write(convert.Uint32Byte(i.IPv4Addresses[j]))
+	}
+}
diff --git a/protocols/isis/packet/tlv_ip_interface_address_test.go b/protocols/isis/packet/tlv_ip_interface_addresses_test.go
similarity index 67%
rename from protocols/isis/packet/tlv_ip_interface_address_test.go
rename to protocols/isis/packet/tlv_ip_interface_addresses_test.go
index 432437ce0b943adec0947b3d247afdad411d15d2..b9e51e3d7f6366bd472cf65f7cff8fd8695f730c 100644
--- a/protocols/isis/packet/tlv_ip_interface_address_test.go
+++ b/protocols/isis/packet/tlv_ip_interface_addresses_test.go
@@ -10,22 +10,22 @@ import (
 func TestNewIPInterfaceAddressTLV(t *testing.T) {
 	tests := []struct {
 		name     string
-		addr     uint32
-		expected *IPInterfaceAddressTLV
+		addrs    []uint32
+		expected *IPInterfaceAddressesTLV
 	}{
 		{
-			name: "Test #1",
-			addr: 100,
-			expected: &IPInterfaceAddressTLV{
-				TLVType:     132,
-				TLVLength:   4,
-				IPv4Address: 100,
+			name:  "Test #1",
+			addrs: []uint32{100},
+			expected: &IPInterfaceAddressesTLV{
+				TLVType:       132,
+				TLVLength:     4,
+				IPv4Addresses: []uint32{100},
 			},
 		},
 	}
 
 	for _, test := range tests {
-		tlv := NewIPInterfaceAddressTLV(test.addr)
+		tlv := NewIPInterfaceAddressesTLV(test.addrs)
 		assert.Equalf(t, test.expected, tlv, "Test %q", test.name)
 	}
 }
@@ -36,7 +36,7 @@ func TestReadIPInterfaceAddressTLV(t *testing.T) {
 		input     []byte
 		tlvLength uint8
 		wantFail  bool
-		expected  *IPInterfaceAddressTLV
+		expected  *IPInterfaceAddressesTLV
 	}{
 		{
 			name: "Full",
@@ -44,10 +44,10 @@ func TestReadIPInterfaceAddressTLV(t *testing.T) {
 				0, 0, 0, 100,
 			},
 			tlvLength: 4,
-			expected: &IPInterfaceAddressTLV{
-				TLVType:     132,
-				TLVLength:   4,
-				IPv4Address: 100,
+			expected: &IPInterfaceAddressesTLV{
+				TLVType:       132,
+				TLVLength:     4,
+				IPv4Addresses: []uint32{100},
 			},
 		},
 		{
@@ -62,7 +62,7 @@ func TestReadIPInterfaceAddressTLV(t *testing.T) {
 
 	for _, test := range tests {
 		buf := bytes.NewBuffer(test.input)
-		tlv, err := readIPInterfaceAddressTLV(buf, 132, test.tlvLength)
+		tlv, err := readIPInterfaceAddressesTLV(buf, 132, test.tlvLength)
 
 		if err != nil {
 			if test.wantFail {
diff --git a/protocols/isis/packet/tlv_is_neighbors.go b/protocols/isis/packet/tlv_is_neighbors.go
index a39db37ef78612473eb1e629ade182425ee0e5be..1296fee65da74f6dc3ca707521583bf83dee0253 100644
--- a/protocols/isis/packet/tlv_is_neighbors.go
+++ b/protocols/isis/packet/tlv_is_neighbors.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
-	"github.com/pkg/errors"
 )
 
 // ISNeighborsTLVType is the type value of an IS Neighbor TLV
@@ -32,7 +32,7 @@ func readISNeighborsTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*ISN
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_lsp_entries.go b/protocols/isis/packet/tlv_lsp_entries.go
new file mode 100644
index 0000000000000000000000000000000000000000..2f0c270e0fe6f5dc11e1249d6959a2dbad5b0c08
--- /dev/null
+++ b/protocols/isis/packet/tlv_lsp_entries.go
@@ -0,0 +1,73 @@
+package packet
+
+import (
+	"bytes"
+
+	"github.com/pkg/errors"
+)
+
+const (
+	// LSPEntriesTLVType is the type value of an LSP Entries TLV
+	LSPEntriesTLVType = uint8(9)
+)
+
+// LSPEntriesTLV is an LSP Entries TLV carried in PSNP/CSNP
+type LSPEntriesTLV struct {
+	TLVType    uint8
+	TLVLength  uint8
+	LSPEntries []*LSPEntry
+}
+
+// Type returns the type of the TLV
+func (l *LSPEntriesTLV) Type() uint8 {
+	return l.TLVType
+}
+
+// Length returns the length of the TLV
+func (l *LSPEntriesTLV) Length() uint8 {
+	return l.TLVLength
+}
+
+// Value returns self
+func (l *LSPEntriesTLV) Value() interface{} {
+	return l
+}
+
+// NewLSPEntriesTLV creates a nbew LSP Entries TLV
+func NewLSPEntriesTLV(LSPEntries []*LSPEntry) *LSPEntriesTLV {
+	return &LSPEntriesTLV{
+		TLVType:    LSPEntriesTLVType,
+		TLVLength:  uint8(len(LSPEntries)) * LSPEntryLen,
+		LSPEntries: LSPEntries,
+	}
+}
+
+// Serialize serializes an LSP Entries TLV
+func (l *LSPEntriesTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(l.TLVType)
+	buf.WriteByte(l.TLVLength)
+	for i := range l.LSPEntries {
+		l.LSPEntries[i].Serialize(buf)
+	}
+}
+
+func readLSPEntriesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*LSPEntriesTLV, error) {
+	pdu := &LSPEntriesTLV{
+		TLVType:    tlvType,
+		TLVLength:  tlvLength,
+		LSPEntries: make([]*LSPEntry, 0, tlvLength/LSPEntryLen),
+	}
+
+	toRead := tlvLength
+	for toRead > 0 {
+		e, err := decodeLSPEntry(buf)
+		if err != nil {
+			return nil, errors.Wrap(err, "Unable to decode LSP Entry")
+		}
+
+		pdu.LSPEntries = append(pdu.LSPEntries, e)
+		toRead -= LSPEntryLen
+	}
+
+	return pdu, nil
+}
diff --git a/protocols/isis/packet/tlv_lsp_entries_test.go b/protocols/isis/packet/tlv_lsp_entries_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..7d3d73856898a8f9b27ea1675791d19b4e4bf793
--- /dev/null
+++ b/protocols/isis/packet/tlv_lsp_entries_test.go
@@ -0,0 +1,92 @@
+package packet
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/bio-routing/bio-rd/protocols/isis/types"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewLSPEntriesTLV(t *testing.T) {
+	tests := []struct {
+		name       string
+		lspEntries []*LSPEntry
+		expected   *LSPEntriesTLV
+	}{
+		{
+			name: "Test #1",
+			lspEntries: []*LSPEntry{
+				{},
+			},
+			expected: &LSPEntriesTLV{
+				TLVType:   9,
+				TLVLength: 16,
+				LSPEntries: []*LSPEntry{
+					{},
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		res := NewLSPEntriesTLV(test.lspEntries)
+		assert.Equalf(t, test.expected, res, "Test %q", test.name)
+	}
+}
+
+func TestReadLSPEntriesTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		input    []byte
+		expected *LSPEntriesTLV
+		wantFail bool
+	}{
+		{
+			name: "Test #1",
+			input: []byte{
+				2, 0, // Remaining Lifetime
+				10, 20, 30, 40, 50, 60, 88, 99, // LSPID
+				0, 0, 0, 22, // Sequence Number
+				2, 0, // LSPChecksum
+			},
+			expected: &LSPEntriesTLV{
+				TLVType:   9,
+				TLVLength: 16,
+				LSPEntries: []*LSPEntry{
+					{
+						RemainingLifetime: 512,
+						LSPID: LSPID{
+							SystemID:     types.SystemID{10, 20, 30, 40, 50, 60},
+							PseudonodeID: 88,
+							LSPNumber:    99,
+						},
+						SequenceNumber: 22,
+						LSPChecksum:    512,
+					},
+				},
+			},
+			wantFail: false,
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(test.input)
+		tlv, err := readLSPEntriesTLV(buf, 9, uint8(len(test.input)))
+		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.Equalf(t, test.expected, tlv, "Test %q", test.name)
+	}
+}
diff --git a/protocols/isis/packet/tlv_p2p_adj_state.go b/protocols/isis/packet/tlv_p2p_adj_state.go
index 696b0282d65bf28018ed6d20aaaca5792810fa28..42cde1a3fe0badcb3859a5f78d0772a13428bb27 100644
--- a/protocols/isis/packet/tlv_p2p_adj_state.go
+++ b/protocols/isis/packet/tlv_p2p_adj_state.go
@@ -2,20 +2,20 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	"github.com/bio-routing/tflow2/convert"
-	"github.com/pkg/errors"
 )
 
 const (
 	// P2PAdjacencyStateTLVType is the type value of an P2P adjacency state TLV
-	P2PAdjacencyStateTLVType = 240
-	// withoutNeighbor is the length of this TLV without a neighbor
-	withoutNeighbor = 5
-	//withNeighbor is the length of this TLV including a neighbor
-	withNeighbor = 15
+	P2PAdjacencyStateTLVType = uint8(240)
+	// P2PAdjacencyStateTLVLenWithoutNeighbor is the length of this TLV without a neighbor
+	P2PAdjacencyStateTLVLenWithoutNeighbor = 5
+	//P2PAdjacencyStateTLVLenWithNeighbor is the length of this TLV including a neighbor
+	P2PAdjacencyStateTLVLenWithNeighbor = 15
 )
 
 // P2PAdjacencyStateTLV represents an P2P adjacency state TLV
@@ -36,12 +36,12 @@ func readP2PAdjacencyStateTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8)
 
 	fields := make([]interface{}, 0)
 	switch pdu.TLVLength {
-	case withoutNeighbor:
+	case P2PAdjacencyStateTLVLenWithoutNeighbor:
 		fields = []interface{}{
 			&pdu.AdjacencyState,
 			&pdu.ExtendedLocalCircuitID,
 		}
-	case withNeighbor:
+	case P2PAdjacencyStateTLVLenWithNeighbor:
 		fields = []interface{}{
 			&pdu.AdjacencyState,
 			&pdu.ExtendedLocalCircuitID,
@@ -52,7 +52,7 @@ func readP2PAdjacencyStateTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8)
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to decode fields")
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
 	}
 
 	return pdu, nil
@@ -62,7 +62,7 @@ func readP2PAdjacencyStateTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8)
 func NewP2PAdjacencyStateTLV(adjacencyState uint8, extendedLocalCircuitID uint32) *P2PAdjacencyStateTLV {
 	return &P2PAdjacencyStateTLV{
 		TLVType:                P2PAdjacencyStateTLVType,
-		TLVLength:              withoutNeighbor,
+		TLVLength:              P2PAdjacencyStateTLVLenWithoutNeighbor,
 		AdjacencyState:         adjacencyState,
 		ExtendedLocalCircuitID: extendedLocalCircuitID,
 	}
@@ -90,7 +90,7 @@ func (p P2PAdjacencyStateTLV) Serialize(buf *bytes.Buffer) {
 	buf.WriteByte(p.AdjacencyState)
 	buf.Write(convert.Uint32Byte(p.ExtendedLocalCircuitID))
 
-	if p.TLVLength == withNeighbor {
+	if p.TLVLength == P2PAdjacencyStateTLVLenWithNeighbor {
 		buf.Write(p.NeighborSystemID[:])
 		buf.Write(convert.Uint32Byte(p.NeighborExtendedLocalCircuitID))
 	}
diff --git a/protocols/isis/packet/tlv_protocols_supported.go b/protocols/isis/packet/tlv_protocols_supported.go
index 7aafbf95af6af9555f180df740f9b86b4633416b..a9597e155d539245a2c0e7fc158bb81311ac8c45 100644
--- a/protocols/isis/packet/tlv_protocols_supported.go
+++ b/protocols/isis/packet/tlv_protocols_supported.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
+	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
-	"github.com/pkg/errors"
 )
 
 // ProtocolsSupportedTLVType is the type value of an protocols supported TLV
@@ -32,7 +32,7 @@ func readProtocolsSupportedTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8
 	for i := uint8(0); i < tlvLength; i++ {
 		err := decode.Decode(buf, fields)
 		if err != nil {
-			return nil, errors.Wrap(err, "Unable to decode fields")
+			return nil, fmt.Errorf("Unable to decode fields: %v", err)
 		}
 		pdu.NetworkLayerProtocolIDs[i] = protoID
 	}
diff --git a/protocols/isis/packet/tlv_traffic_engineering_router_id.go b/protocols/isis/packet/tlv_traffic_engineering_router_id.go
new file mode 100644
index 0000000000000000000000000000000000000000..0720607b586fe9b22a70990c1d945b571971ae3f
--- /dev/null
+++ b/protocols/isis/packet/tlv_traffic_engineering_router_id.go
@@ -0,0 +1,69 @@
+package packet
+
+import (
+	"bytes"
+	"fmt"
+
+	"github.com/bio-routing/bio-rd/util/decode"
+)
+
+const (
+	// TrafficEngineeringRouterIDTLVType is the type value of an Traffic Engineering Router ID TLV
+	TrafficEngineeringRouterIDTLVType = 134
+)
+
+// TrafficEngineeringRouterIDTLV is a Traffic Engineering Router ID TLV
+type TrafficEngineeringRouterIDTLV struct {
+	TLVType   uint8
+	TLVLength uint8
+	Address   [4]byte
+}
+
+// NewTrafficEngineeringRouterIDTLV creates a new TrafficEngineeringRouterIDTLV
+func NewTrafficEngineeringRouterIDTLV(addr [4]byte) *TrafficEngineeringRouterIDTLV {
+	return &TrafficEngineeringRouterIDTLV{
+		TLVType:   TrafficEngineeringRouterIDTLVType,
+		TLVLength: 4,
+		Address:   addr,
+	}
+}
+
+// Serialize serializes a TrafficEngineeringRouterIDTLV
+func (t *TrafficEngineeringRouterIDTLV) Serialize(buf *bytes.Buffer) {
+	buf.WriteByte(t.TLVType)
+	buf.WriteByte(t.TLVLength)
+	buf.Write(t.Address[:])
+}
+
+func readTrafficEngineeringRouterIDTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*TrafficEngineeringRouterIDTLV, error) {
+	pdu := &TrafficEngineeringRouterIDTLV{
+		TLVType:   tlvType,
+		TLVLength: tlvLength,
+	}
+
+	fields := []interface{}{
+		pdu.Address[:],
+	}
+
+	err := decode.Decode(buf, fields)
+	if err != nil {
+		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+	}
+
+	return pdu, nil
+}
+
+// Type gets the type of the TLV
+func (t TrafficEngineeringRouterIDTLV) Type() uint8 {
+	return t.TLVType
+}
+
+// Length gets the length of the TLV
+func (t TrafficEngineeringRouterIDTLV) Length() uint8 {
+	return t.TLVLength
+}
+
+// Value gets the TLV itself
+func (t TrafficEngineeringRouterIDTLV) Value() interface{} {
+	return t
+}
diff --git a/protocols/isis/packet/tlv_traffic_engineering_router_id_test.go b/protocols/isis/packet/tlv_traffic_engineering_router_id_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..51875f6a4f146fd7d637505d295386b6f020612b
--- /dev/null
+++ b/protocols/isis/packet/tlv_traffic_engineering_router_id_test.go
@@ -0,0 +1,100 @@
+package packet
+
+import (
+	"bytes"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewTrafficEngineeringRouterIDTLV(t *testing.T) {
+	tests := []struct {
+		name     string
+		addr     [4]byte
+		expected *TrafficEngineeringRouterIDTLV
+	}{
+		{
+			name: "Test #1",
+			addr: [4]byte{10, 20, 30, 40},
+			expected: &TrafficEngineeringRouterIDTLV{
+				TLVType:   134,
+				TLVLength: 4,
+				Address:   [4]byte{10, 20, 30, 40},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		tlv := NewTrafficEngineeringRouterIDTLV(test.addr)
+		assert.Equal(t, test.expected, tlv, test.name)
+	}
+}
+
+func TestTrafficEngineeringRouterIDTLVSerialize(t *testing.T) {
+	tests := []struct {
+		name     string
+		tlv      *TrafficEngineeringRouterIDTLV
+		expected []byte
+	}{
+		{
+			name: "Test #1",
+			tlv: &TrafficEngineeringRouterIDTLV{
+				TLVType:   134,
+				TLVLength: 4,
+				Address:   [4]byte{10, 0, 0, 123},
+			},
+			expected: []byte{134, 4, 10, 0, 0, 123},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(nil)
+		test.tlv.Serialize(buf)
+		assert.Equal(t, test.expected, buf.Bytes(), test.name)
+	}
+}
+
+func TestReadTrafficEngineeringRouterIDTLV(t *testing.T) {
+	tests := []struct {
+		name      string
+		tlvType   uint8
+		tlvLength uint8
+		pkt       []byte
+		expected  *TrafficEngineeringRouterIDTLV
+		wantFail  bool
+	}{
+		{
+			name:      "Normal packet",
+			tlvType:   134,
+			tlvLength: 4,
+			pkt: []byte{
+				1, 2, 3, 4,
+			},
+			expected: &TrafficEngineeringRouterIDTLV{
+				TLVType:   134,
+				TLVLength: 4,
+				Address:   [4]byte{1, 2, 3, 4},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		buf := bytes.NewBuffer(test.pkt)
+		tlv, err := readTrafficEngineeringRouterIDTLV(buf, test.tlvType, test.tlvLength)
+		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, tlv, test.name)
+	}
+}
diff --git a/protocols/isis/packet/tlv_unknown.go b/protocols/isis/packet/tlv_unknown.go
index 08e8ae35fb254ebdcf5e09d926f0c8a83ed1f8e4..13a469d63ba311b5bd5c2f87398a442ca52fdd2d 100644
--- a/protocols/isis/packet/tlv_unknown.go
+++ b/protocols/isis/packet/tlv_unknown.go
@@ -3,8 +3,6 @@ package packet
 import (
 	"bytes"
 	"fmt"
-
-	"github.com/pkg/errors"
 )
 
 // UnknownTLV represents an unknown TLV
@@ -23,11 +21,11 @@ func readUnknownTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Unknown
 
 	n, err := buf.Read(pdu.TLVValue)
 	if err != nil {
-		return nil, errors.Wrap(err, "Unable to read")
+		return nil, fmt.Errorf("Unable to read: %v", err)
 	}
 
 	if n != int(tlvLength) {
-		return nil, fmt.Errorf("Read incomplete")
+		return nil, fmt.Errorf("Read of TLVType %d incomplete", pdu.TLVType)
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/types/isis.go b/protocols/isis/types/isis.go
index 94fe12a41105314e0f4b62f4423face3fdeee9c8..c5c0d5a0895e54c12fd2598b55164f2ea7c8ab5a 100644
--- a/protocols/isis/types/isis.go
+++ b/protocols/isis/types/isis.go
@@ -5,9 +5,35 @@ import "fmt"
 // SystemID is an ISIS System ID
 type SystemID [6]byte
 
+// SourceID is a source ID
+type SourceID struct {
+	SystemID  SystemID
+	CircuitID uint8
+}
+
+// MACAddress is an Ethernet MAC address
+type MACAddress [6]byte
+
 // AreaID is an ISIS Area ID
 type AreaID []byte
 
 func (sysID *SystemID) String() string {
 	return fmt.Sprintf("%d%d.%d%d.%d%d", sysID[0], sysID[1], sysID[2], sysID[3], sysID[4], sysID[5])
 }
+
+// NewSourceID creates a new SourceID
+func NewSourceID(sysID SystemID, circuitID uint8) SourceID {
+	return SourceID{
+		SystemID:  sysID,
+		CircuitID: circuitID,
+	}
+}
+
+// Serialize serializes a source ID
+func (srcID *SourceID) Serialize() []byte {
+	return []byte{
+		srcID.SystemID[0], srcID.SystemID[1], srcID.SystemID[2],
+		srcID.SystemID[3], srcID.SystemID[4], srcID.SystemID[5],
+		srcID.CircuitID,
+	}
+}