Skip to content
Snippets Groups Projects
Commit cdc5471d authored by Oliver Herms's avatar Oliver Herms
Browse files

Added some data strcutures and their deserialization

parent e9e5c326
No related branches found
No related tags found
No related merge requests found
Showing
with 1289 additions and 13 deletions
......@@ -2,27 +2,20 @@ package main
import (
"fmt"
"net"
"time"
"github.com/sirupsen/logrus"
"github.com/bio-routing/bio-rd/protocols/bgp/server"
"github.com/bio-routing/bio-rd/protocols/bmp/server"
"github.com/bio-routing/bio-rd/routingtable/locRIB"
bnet "github.com/bio-routing/bio-rd/net"
"github.com/sirupsen/logrus"
)
func strAddr(s string) uint32 {
ret, _ := bnet.StrToAddr(s)
return ret
}
func main() {
logrus.Printf("This is a BGP speaker\n")
logrus.Printf("This is a BMP speaker\n")
rib := locRIB.New()
b := server.NewBgpServer()
startServer(b, rib)
b := server.NewServer()
b.AddRouter(net.IP{127, 0, 0, 1}, 1234, rib, nil)
go func() {
for {
......
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
"github.com/bio-routing/tflow2/convert"
)
const (
CommonHeaderLen = 6
)
type CommonHeader struct {
Version uint8
MsgLength uint32
MsgType uint8
}
func (c *CommonHeader) Serialize(buf *bytes.Buffer) {
buf.WriteByte(c.Version)
buf.Write(convert.Uint32Byte(c.MsgLength))
buf.WriteByte(c.MsgType)
}
func decodeCommonHeader(buf *bytes.Buffer) (*CommonHeader, error) {
ch := &CommonHeader{}
fields := []interface{}{
&ch.Version,
&ch.MsgLength,
&ch.MsgType,
}
err := decoder.Decode(buf, fields)
if err != nil {
return ch, err
}
return ch, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCommonHeaderSerialize(t *testing.T) {
tests := []struct {
name string
input *CommonHeader
expected []byte
}{
{
name: "Test #1",
input: &CommonHeader{
Version: 3,
MsgLength: 100,
MsgType: 10,
},
expected: []byte{3, 0, 0, 0, 100, 10},
},
}
for _, test := range tests {
buf := bytes.NewBuffer(nil)
test.input.Serialize(buf)
assert.Equalf(t, test.expected, buf.Bytes(), "Test %q", test.name)
}
}
func TestDecodeCommonHeader(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *CommonHeader
}{
{
name: "Full packet",
input: []byte{
3, 0, 0, 0, 100, 10,
},
wantFail: false,
expected: &CommonHeader{
Version: 3,
MsgLength: 100,
MsgType: 10,
},
},
{
name: "Incomplete",
input: []byte{
3, 0, 0, 0, 100,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
ch, err := decodeCommonHeader(buf)
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, ch, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
)
type Msg interface {
MsgType() uint8
}
const (
MinLen = 6
RouteMonitoringType = 0
StatisticsReportType = 1
PeerDownNotificationType = 2
PeerUpNotificationType = 3
InitiationMessageType = 4
TerminationMessageType = 5
RouteMirroringMessageType = 6
BGPMessage = 0
BGPInformation = 1
ErroredPDU = 0
MessageLost = 1
)
// Decode decodes a BMP message
func Decode(msg []byte) (Msg, error) {
buf := bytes.NewBuffer(msg)
ch, err := decodeCommonHeader(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode common header: %v", err)
}
if ch.Version != 3 {
return nil, fmt.Errorf("Unsupported BMP version: %d", ch.Version)
}
switch ch.MsgType {
case RouteMonitoringType:
case StatisticsReportType:
sr, err := decodeStatsReport(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode stats report: %v", err)
}
return sr, nil
case PeerDownNotificationType:
pd, err := decodePeerUpNotification(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode peer down notification: %v", err)
}
return pd, nil
case PeerUpNotificationType:
pu, err := decodePeerUpNotification(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode peer up notification: %v", err)
}
return pu, nil
case InitiationMessageType:
im, err := decodeInitiationMessage(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decode initiation message: %v", err)
}
return im, nil
case TerminationMessageType:
tm, err := decodeTerminationMessage(buf, ch)
if err != nil {
return nil, fmt.Errorf("Unable to decide termination message: %v", err)
}
return tm, nil
case RouteMirroringMessageType:
default:
return nil, fmt.Errorf("Unexpected message type: %d", ch.MsgType)
}
return nil, fmt.Errorf("Unexpected message type: %d", ch.MsgType)
}
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
)
const (
MinInformationTLVLen = 4
)
// InformationTLV represents an information TLV
type InformationTLV struct {
InformationType uint16
InformationLength uint16
Information []byte
}
func decodeInformationTLV(buf *bytes.Buffer) (*InformationTLV, error) {
infoTLV := &InformationTLV{}
fields := []interface{}{
&infoTLV.InformationType,
&infoTLV.InformationLength,
}
err := decoder.Decode(buf, fields)
if err != nil {
return infoTLV, err
}
infoTLV.Information = make([]byte, infoTLV.InformationLength)
fields = []interface{}{
&infoTLV.Information,
}
err = decoder.Decode(buf, fields)
if err != nil {
return infoTLV, err
}
return infoTLV, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeInformationTLV(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *InformationTLV
}{
{
name: "Full",
input: []byte{
0, 10, 0, 5,
1, 2, 3, 4, 5,
},
wantFail: false,
expected: &InformationTLV{
InformationType: 10,
InformationLength: 5,
Information: []byte{1, 2, 3, 4, 5},
},
},
{
name: "Incomplete",
input: []byte{
0, 10, 0, 5,
1, 2, 3, 4,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
infoTLV, err := decodeInformationTLV(buf)
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, infoTLV, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
)
// InitiationMessage represents an initiation message
type InitiationMessage struct {
CommonHeader *CommonHeader
TLVs []*InformationTLV
}
// MsgType returns the type of this message
func (im *InitiationMessage) MsgType() uint8 {
return im.CommonHeader.MsgType
}
// SetCommonHeader sets the common header
func (im *InitiationMessage) SetCommonHeader(ch *CommonHeader) {
im.CommonHeader = ch
}
func decodeInitiationMessage(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
im := &InitiationMessage{
TLVs: make([]*InformationTLV, 0, 2),
}
read := uint32(0)
toRead := ch.MsgLength - CommonHeaderLen
for read < toRead {
tlv, err := decodeInformationTLV(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode TLV: %v", err)
}
im.TLVs = append(im.TLVs, tlv)
read += uint32(tlv.InformationLength) + MinInformationTLVLen
fmt.Printf("read: %d\n", read)
}
return im, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeInitiationMessage(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *InitiationMessage
}{
{
name: "Full",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, 43, // BBBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: false,
expected: &InitiationMessage{
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 4,
Information: []byte{42, 42, 42, 42},
},
{
InformationType: 2,
InformationLength: 5,
Information: []byte{43, 43, 43, 43, 43},
},
},
},
},
{
name: "Incomplete",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, // BBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
im, err := decodeInitiationMessage(buf, test.ch)
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, im, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
)
// PeerDownNotification represents a peer down notification
type PeerDownNotification struct {
CommonHeader *CommonHeader
Reason uint8
Data []byte
}
// MsgType returns the type of this message
func (p *PeerDownNotification) MsgType() uint8 {
return p.CommonHeader.MsgType
}
func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownNotification, error) {
p := &PeerDownNotification{}
fields := []interface{}{
&p.Reason,
}
err := decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
if p.Reason < 1 || p.Reason > 3 {
return p, nil
}
p.Data = make([]byte, ch.MsgLength-CommonHeaderLen-1)
fields = []interface{}{
p.Data,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
return p, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodePeerDownNotification(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *PeerDownNotification
}{
{
name: "Full",
input: []byte{
1,
1, 2, 3,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 4,
},
wantFail: false,
expected: &PeerDownNotification{
Reason: 1,
Data: []byte{
1, 2, 3,
},
},
},
{
name: "Full no data",
input: []byte{
4,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 4,
},
wantFail: false,
expected: &PeerDownNotification{
Reason: 4,
Data: nil,
},
},
{
name: "Incomplete data",
input: []byte{
1,
1, 2, 3,
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 5,
},
wantFail: true,
},
{
name: "Incomplete",
input: []byte{},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 5,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
p, err := decodePeerDownNotification(buf, test.ch)
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, p, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
"github.com/bio-routing/bio-rd/util/decoder"
)
const (
OpenMsgMinLen = 10
)
// PeerUpNotification represents a peer up notification
type PeerUpNotification struct {
CommonHeader *CommonHeader
LocalAddress [16]byte
LocalPort uint16
RemotePort uint16
SentOpenMsg []byte
ReceivedOpenMsg []byte
Information []byte
}
// MsgType returns the type of this message
func (p *PeerUpNotification) MsgType() uint8 {
return p.CommonHeader.MsgType
}
func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotification, error) {
p := &PeerUpNotification{}
fields := []interface{}{
&p.LocalAddress,
&p.LocalPort,
&p.RemotePort,
}
err := decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
sentOpenMsg, err := getOpenMsg(buf)
if err != nil {
return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
}
p.SentOpenMsg = sentOpenMsg
recvOpenMsg, err := getOpenMsg(buf)
if err != nil {
return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
}
p.ReceivedOpenMsg = recvOpenMsg
if buf.Len() == 0 {
return p, nil
}
p.Information = make([]byte, buf.Len())
fields = []interface{}{
&p.Information,
}
err = decoder.Decode(buf, fields)
if err != nil {
return nil, err
}
fmt.Printf("%v\n", p.Information)
return p, nil
}
func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
msg := make([]byte, OpenMsgMinLen)
_, err := buf.Read(msg)
if err != nil {
return nil, fmt.Errorf("Unable to read: %v", err)
}
if msg[OpenMsgMinLen-1] == 0 {
return msg, nil
}
optParams := make([]byte, msg[OpenMsgMinLen-1])
_, err = buf.Read(optParams)
if err != nil {
return nil, fmt.Errorf("Unable to read: %v", err)
}
msg = append(msg, optParams...)
return msg, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodePeerUp(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *PeerUpNotification
}{
{
name: "Full",
input: []byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 100,
0, 200,
// OPEN Sent
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
5, // Opt Parm Len
1, 2, 3, 4, 5,
// OPEN Recv
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
0, // Opt Parm Len
120, 140, 160, // Information
},
ch: &CommonHeader{
MsgLength: 47,
},
wantFail: false,
expected: &PeerUpNotification{
LocalAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
LocalPort: 100,
RemotePort: 200,
SentOpenMsg: []byte{
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
5, // Opt Parm Len
1, 2, 3, 4, 5,
},
ReceivedOpenMsg: []byte{
// OPEN Recv
4, // Version
1, 0, // ASN
2, 0, // Hold Time
100, 110, 120, 130, // BGP Identifier
0, // Opt Parm Len
},
Information: []byte{
120, 140, 160, // Information
},
},
},
{
name: "Incomplete #1",
input: []byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 100,
},
ch: &CommonHeader{
MsgLength: 47,
},
wantFail: true,
},
{
name: "Incomplete #2",
input: []byte{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 100,
0, 200,
// OPEN Sent
4, // Version
1, 0, // ASN
2, 0, // Hold Time
},
ch: &CommonHeader{
MsgLength: 47,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
pu, err := decodePeerUpNotification(buf, test.ch)
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, pu, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"github.com/bio-routing/bio-rd/util/decoder"
"github.com/bio-routing/tflow2/convert"
)
// PerPeerHeader represents a BMP per peer header
type PerPeerHeader struct {
PeerType uint8
PeerFlags uint8
PeerDistinguisher uint32
PeerAddress [16]byte
PeerAS uint32
PeerBGPID uint32
Timestamp uint32
TimestampMicroSeconds uint32
}
// Serialize serializes a per peer header
func (p *PerPeerHeader) Serialize(buf *bytes.Buffer) {
buf.WriteByte(p.PeerType)
buf.WriteByte(p.PeerFlags)
buf.Write(convert.Uint32Byte(p.PeerDistinguisher))
buf.Write(p.PeerAddress[:])
buf.Write(convert.Uint32Byte(p.PeerAS))
buf.Write(convert.Uint32Byte(p.PeerBGPID))
buf.Write(convert.Uint32Byte(p.Timestamp))
buf.Write(convert.Uint32Byte(p.TimestampMicroSeconds))
}
func decodePerPeerHeader(buf *bytes.Buffer) (*PerPeerHeader, error) {
p := &PerPeerHeader{}
fields := []interface{}{
&p.PeerType,
&p.PeerFlags,
&p.PeerDistinguisher,
&p.PeerAddress,
&p.PeerAS,
&p.PeerBGPID,
&p.Timestamp,
&p.TimestampMicroSeconds,
}
err := decoder.Decode(buf, fields)
if err != nil {
return p, err
}
return p, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPerPeerHeaderSerialize(t *testing.T) {
tests := []struct {
name string
input *PerPeerHeader
expected []byte
}{
{
name: "Test #1",
input: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
expected: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
},
},
}
for _, test := range tests {
buf := bytes.NewBuffer(nil)
test.input.Serialize(buf)
res := buf.Bytes()
assert.Equalf(t, test.expected, res, "Test %q", test.name)
}
}
func TestDecodePerPeerHeader(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *PerPeerHeader
}{
{
name: "Full packet",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
},
wantFail: false,
expected: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
},
{
name: "Incomplete",
input: []byte{
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
p, err := decodePerPeerHeader(buf)
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, p, "Test %q", test.name)
}
}
package packet
package packet
package packet
import (
"bytes"
"fmt"
"github.com/bio-routing/bio-rd/util/decoder"
)
// StatsReport represents a stats report message
type StatsReport struct {
CommonHeader *CommonHeader
PerPeerHeader *PerPeerHeader
StatsCount uint32
Stats []*InformationTLV
}
// MsgType returns the type of this message
func (s *StatsReport) MsgType() uint8 {
return s.CommonHeader.MsgType
}
// SetCommonHeader sets the common header
func (s *StatsReport) SetCommonHeader(ch *CommonHeader) {
s.CommonHeader = ch
}
func decodeStatsReport(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
sr := &StatsReport{
CommonHeader: ch,
}
pph, err := decodePerPeerHeader(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
}
sr.PerPeerHeader = pph
fields := []interface{}{
&sr.StatsCount,
}
err = decoder.Decode(buf, fields)
if err != nil {
return sr, err
}
sr.Stats = make([]*InformationTLV, sr.StatsCount)
for i := uint32(0); i < sr.StatsCount; i++ {
infoTLV, err := decodeInformationTLV(buf)
if err != nil {
return sr, fmt.Errorf("Unable to decode information TLV: %v", err)
}
sr.Stats[i] = infoTLV
}
return sr, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeStatsReport(t *testing.T) {
tests := []struct {
name string
input []byte
wantFail bool
expected *StatsReport
}{
{
name: "Full",
input: []byte{
// Per Peer Header
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
// Stats Count
0, 0, 0, 2,
0, 1,
0, 4,
0, 0, 0, 2,
0, 2,
0, 4,
0, 0, 0, 3,
},
wantFail: false,
expected: &StatsReport{
PerPeerHeader: &PerPeerHeader{
PeerType: 1,
PeerFlags: 2,
PeerDistinguisher: 3,
PeerAddress: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
PeerAS: 51324,
PeerBGPID: 123,
Timestamp: 100,
TimestampMicroSeconds: 200,
},
StatsCount: 2,
Stats: []*InformationTLV{
{
InformationType: 1,
InformationLength: 4,
Information: []byte{0, 0, 0, 2},
},
{
InformationType: 2,
InformationLength: 4,
Information: []byte{0, 0, 0, 3},
},
},
},
},
{
name: "Incomplete per peer header",
input: []byte{
// Per Peer Header
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
},
wantFail: true,
},
{
name: "Incomplete stats count",
input: []byte{
// Per Peer Header
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
},
wantFail: true,
},
{
name: "Incomplete TLV",
input: []byte{
// Per Peer Header
1,
2,
0, 0, 0, 3,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
0, 0, 200, 124,
0, 0, 0, 123,
0, 0, 0, 100,
0, 0, 0, 200,
// Stats Count
0, 0, 0, 2,
0, 1,
0, 4,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
sr, err := decodeStatsReport(buf, nil)
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, sr, "Test %q", test.name)
}
}
package packet
import (
"bytes"
"fmt"
)
// TerminationMessage represents a termination message
type TerminationMessage struct {
CommonHeader *CommonHeader
TLVs []*InformationTLV
}
// MsgType returns the type of this message
func (t *TerminationMessage) MsgType() uint8 {
return t.CommonHeader.MsgType
}
func decodeTerminationMessage(buf *bytes.Buffer, ch *CommonHeader) (*TerminationMessage, error) {
tm := &TerminationMessage{
TLVs: make([]*InformationTLV, 0, 2),
}
read := uint32(0)
toRead := ch.MsgLength - CommonHeaderLen
for read < toRead {
tlv, err := decodeInformationTLV(buf)
if err != nil {
return nil, fmt.Errorf("Unable to decode TLV: %v", err)
}
tm.TLVs = append(tm.TLVs, tlv)
read += uint32(tlv.InformationLength) + MinInformationTLVLen
}
return tm, nil
}
package packet
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestDecodeTerminationMessage(t *testing.T) {
tests := []struct {
name string
input []byte
ch *CommonHeader
wantFail bool
expected *TerminationMessage
}{
{
name: "Full",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, 43, // BBBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: false,
expected: &TerminationMessage{
TLVs: []*InformationTLV{
{
InformationType: 1,
InformationLength: 4,
Information: []byte{42, 42, 42, 42},
},
{
InformationType: 2,
InformationLength: 5,
Information: []byte{43, 43, 43, 43, 43},
},
},
},
},
{
name: "Incomplete",
input: []byte{
0, 1, // sysDescr
0, 4, // Length
42, 42, 42, 42, // AAAA
0, 2, //sysName
0, 5, // Length
43, 43, 43, 43, // BBBB
},
ch: &CommonHeader{
MsgLength: CommonHeaderLen + 17,
},
wantFail: true,
},
}
for _, test := range tests {
buf := bytes.NewBuffer(test.input)
im, err := decodeTerminationMessage(buf, test.ch)
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, im, "Test %q", test.name)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment