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, + } +}