summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-05-17 11:07:18 +0900
committerIWASE Yusuke <iwase.yusuke0@gmail.com>2017-05-22 13:12:02 +0900
commit5bb073815657d605c77376a51e6219a593eb7af6 (patch)
tree08a6539364618a0cffc42c4930831937b21b1510
parentfa1378f58bb6306e0c327f2a69a798a46c9865a4 (diff)
packet/bmp: Implement BMPStatisticsReport serializer
Currently, only parser for BMPStatisticsReport is implemented and does not support the per-AFI/SAFI stats TLV types. This patch implements BMPStatisticsReport serializer and re-implements the stats TLV parser/serializer to support the missing TLV types. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
-rw-r--r--packet/bmp/bmp.go207
-rw-r--r--packet/bmp/bmp_test.go13
2 files changed, 181 insertions, 39 deletions
diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go
index d931643c..3cdccf46 100644
--- a/packet/bmp/bmp.go
+++ b/packet/bmp/bmp.go
@@ -195,15 +195,181 @@ const (
BMP_STAT_TYPE_DUPLICATE_UPDATE
)
+type BMPStatsTLVInterface interface {
+ ParseValue([]byte) error
+ Serialize() ([]byte, error)
+}
+
type BMPStatsTLV struct {
Type uint16
Length uint16
- Value uint64
+}
+
+type BMPStatsTLV32 struct {
+ BMPStatsTLV
+ Value uint32
+}
+
+func NewBMPStatsTLV32(t uint16, v uint32) *BMPStatsTLV32 {
+ return &BMPStatsTLV32{
+ BMPStatsTLV: BMPStatsTLV{
+ Type: t,
+ Length: 4,
+ },
+ Value: v,
+ }
+}
+
+func (s *BMPStatsTLV32) ParseValue(data []byte) error {
+ if s.Length != 4 {
+ return fmt.Errorf("invalid lengh: %d bytes (%d bytes expected)", s.Length, 4)
+ }
+ s.Value = binary.BigEndian.Uint32(data[:8])
+ return nil
+}
+
+func (s *BMPStatsTLV32) Serialize() ([]byte, error) {
+ buf := make([]byte, 8)
+ binary.BigEndian.PutUint16(buf[0:2], s.Type)
+ binary.BigEndian.PutUint16(buf[2:4], 4)
+ binary.BigEndian.PutUint32(buf[4:8], s.Value)
+ return buf, nil
+}
+
+type BMPStatsTLV64 struct {
+ BMPStatsTLV
+ Value uint64
+}
+
+func NewBMPStatsTLV64(t uint16, v uint64) *BMPStatsTLV64 {
+ return &BMPStatsTLV64{
+ BMPStatsTLV: BMPStatsTLV{
+ Type: t,
+ Length: 8,
+ },
+ Value: v,
+ }
+}
+
+func (s *BMPStatsTLV64) ParseValue(data []byte) error {
+ if s.Length != 8 {
+ return fmt.Errorf("invalid lengh: %d bytes (%d bytes expected)", s.Length, 8)
+ }
+ s.Value = binary.BigEndian.Uint64(data[:8])
+ return nil
+}
+
+func (s *BMPStatsTLV64) Serialize() ([]byte, error) {
+ buf := make([]byte, 12)
+ binary.BigEndian.PutUint16(buf[0:2], s.Type)
+ binary.BigEndian.PutUint16(buf[2:4], 8)
+ binary.BigEndian.PutUint64(buf[4:12], s.Value)
+ return buf, nil
+}
+
+type BMPStatsTLVPerAfiSafi64 struct {
+ BMPStatsTLV
+ AFI uint16
+ SAFI uint8
+ Value uint64
+}
+
+func NewBMPStatsTLVPerAfiSafi64(t uint16, afi uint16, safi uint8, v uint64) *BMPStatsTLVPerAfiSafi64 {
+ return &BMPStatsTLVPerAfiSafi64{
+ BMPStatsTLV: BMPStatsTLV{
+ Type: t,
+ Length: 11,
+ },
+ AFI: afi,
+ SAFI: safi,
+ Value: v,
+ }
+}
+
+func (s *BMPStatsTLVPerAfiSafi64) ParseValue(data []byte) error {
+ if s.Length != 11 {
+ return fmt.Errorf("invalid lengh: %d bytes (%d bytes expected)", s.Length, 11)
+ }
+ s.AFI = binary.BigEndian.Uint16(data[0:2])
+ s.SAFI = data[2]
+ s.Value = binary.BigEndian.Uint64(data[3:11])
+ return nil
+}
+
+func (s *BMPStatsTLVPerAfiSafi64) Serialize() ([]byte, error) {
+ buf := make([]byte, 15)
+ binary.BigEndian.PutUint16(buf[0:2], s.Type)
+ binary.BigEndian.PutUint16(buf[2:4], 11)
+ binary.BigEndian.PutUint16(buf[4:6], s.AFI)
+ buf[6] = s.SAFI
+ binary.BigEndian.PutUint64(buf[7:15], s.Value)
+ return buf, nil
}
type BMPStatisticsReport struct {
Count uint32
- Stats []BMPStatsTLV
+ Stats []BMPStatsTLVInterface
+}
+
+func NewBMPStatisticsReport(p BMPPeerHeader, stats []BMPStatsTLVInterface) *BMPMessage {
+ return &BMPMessage{
+ Header: BMPHeader{
+ Version: BMP_VERSION,
+ Type: BMP_MSG_STATISTICS_REPORT,
+ },
+ PeerHeader: p,
+ Body: &BMPStatisticsReport{
+ Count: uint32(len(stats)),
+ Stats: stats,
+ },
+ }
+}
+
+func (body *BMPStatisticsReport) ParseBody(msg *BMPMessage, data []byte) error {
+ body.Count = binary.BigEndian.Uint32(data[0:4])
+ data = data[4:]
+ for len(data) >= 4 {
+ tl := BMPStatsTLV{
+ Type: binary.BigEndian.Uint16(data[0:2]),
+ Length: binary.BigEndian.Uint16(data[2:4]),
+ }
+ data = data[4:]
+ if len(data) < int(tl.Length) {
+ return fmt.Errorf("value lengh is not enough: %d bytes (%d bytes expected)", len(data), tl.Length)
+ }
+ var s BMPStatsTLVInterface
+ var err error = nil
+ if tl.Type == BMP_STAT_TYPE_ADJ_RIB_IN || tl.Type == BMP_STAT_TYPE_LOC_RIB {
+ s = &BMPStatsTLV64{BMPStatsTLV: tl}
+ err = s.ParseValue(data)
+ } else if tl.Type == BMP_STAT_TYPE_PER_AFI_SAFI_ADJ_RIB_IN || tl.Type == BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB {
+ s = &BMPStatsTLVPerAfiSafi64{BMPStatsTLV: tl}
+ err = s.ParseValue(data)
+ } else {
+ s = &BMPStatsTLV32{BMPStatsTLV: tl}
+ err = s.ParseValue(data)
+ }
+ if err != nil {
+ return err
+ }
+ body.Stats = append(body.Stats, s)
+ data = data[tl.Length:]
+ }
+ return nil
+}
+
+func (body *BMPStatisticsReport) Serialize() ([]byte, error) {
+ buf := make([]byte, 4)
+ body.Count = uint32(len(body.Stats))
+ binary.BigEndian.PutUint32(buf[0:4], body.Count)
+ for _, tlv := range body.Stats {
+ tlvBuf, err := tlv.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, tlvBuf...)
+ }
+ return buf, nil
}
const (
@@ -350,43 +516,6 @@ func (body *BMPPeerUpNotification) Serialize() ([]byte, error) {
return buf, nil
}
-func (body *BMPStatisticsReport) ParseBody(msg *BMPMessage, data []byte) error {
- body.Count = binary.BigEndian.Uint32(data[0:4])
- data = data[4:]
- for len(data) >= 4 {
- s := BMPStatsTLV{}
- s.Type = binary.BigEndian.Uint16(data[0:2])
- s.Length = binary.BigEndian.Uint16(data[2:4])
- data = data[4:]
- if len(data) < int(s.Length) {
- break
- }
- if s.Type == BMP_STAT_TYPE_ADJ_RIB_IN || s.Type == BMP_STAT_TYPE_LOC_RIB {
- if s.Length < 8 {
- break
- }
- s.Value = binary.BigEndian.Uint64(data[:8])
- } else {
- if s.Length < 4 {
- break
- }
- s.Value = uint64(binary.BigEndian.Uint32(data[:4]))
- }
- body.Stats = append(body.Stats, s)
- data = data[s.Length:]
- }
- return nil
-}
-
-func (body *BMPStatisticsReport) Serialize() ([]byte, error) {
- // TODO
- buf := make([]byte, 4)
- body.Count = uint32(len(body.Stats))
- binary.BigEndian.PutUint32(buf[0:4], body.Count)
-
- return buf, nil
-}
-
const (
BMP_INIT_TLV_TYPE_STRING = iota
BMP_INIT_TLV_TYPE_SYS_DESCR
diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go
index 3d7737e0..5e70710f 100644
--- a/packet/bmp/bmp_test.go
+++ b/packet/bmp/bmp_test.go
@@ -67,6 +67,19 @@ func Test_RouteMonitoring(t *testing.T) {
verify(t, NewBMPRouteMonitoring(*p0, m))
}
+func Test_StatisticsReport(t *testing.T) {
+ p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
+ s0 := NewBMPStatisticsReport(
+ *p0,
+ []BMPStatsTLVInterface{
+ NewBMPStatsTLV32(BMP_STAT_TYPE_REJECTED, 100),
+ NewBMPStatsTLV64(BMP_STAT_TYPE_ADJ_RIB_IN, 200),
+ NewBMPStatsTLVPerAfiSafi64(BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB, bgp.AFI_IP, bgp.SAFI_UNICAST, 300),
+ },
+ )
+ verify(t, s0)
+}
+
func Test_BogusHeader(t *testing.T) {
h, err := ParseBMPMessage(make([]byte, 10))
assert.Nil(t, h)