From d936841fb3238cc9ad0f728e1c929c8fad783290 Mon Sep 17 00:00:00 2001 From: IWASE Yusuke Date: Mon, 22 May 2017 15:00:28 +0900 Subject: [PATCH] bmp: Implement Information TLV on Initiation message Currently, the TLV fields are implemented as BMPTLV on the Initiation messages, but not enough decoded and required to be constructed in binary format. This patch introduces BMPInfoTLV and makes easy to handle the TLV fields. Note: This patch obsoletes BMPTLV structure. Signed-off-by: IWASE Yusuke --- packet/bmp/bmp.go | 121 +++++++++++++++++++++++++++-------------- packet/bmp/bmp_test.go | 6 +- server/bmp.go | 2 +- 3 files changed, 86 insertions(+), 43 deletions(-) diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go index ba517bda..e93ae61e 100644 --- a/packet/bmp/bmp.go +++ b/packet/bmp/bmp.go @@ -519,58 +519,73 @@ const ( BMP_INIT_TLV_TYPE_SYS_NAME ) -const ( - BMP_TERM_TLV_TYPE_STRING = iota - BMP_TERM_TLV_TYPE_REASON -) - -const ( - BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG = iota - BMP_ROUTE_MIRRORING_TLV_TYPE_INFO -) - -type BMPTLV struct { - Type uint16 - Length uint16 - Value []byte +type BMPInfoTLVInterface interface { + ParseValue([]byte) error + Serialize() ([]byte, error) } -func NewBMPTLV(t uint16, v []byte) *BMPTLV { - return &BMPTLV{ - Type: t, - Length: uint16(len(v)), - Value: v, +type BMPInfoTLV struct { + Type uint16 + Length uint16 +} + +type BMPInfoTLVString struct { + BMPInfoTLV + Value string +} + +func NewBMPInfoTLVString(t uint16, v string) *BMPInfoTLVString { + return &BMPInfoTLVString{ + BMPInfoTLV: BMPInfoTLV{Type: t}, + Value: v, } } -func (tlv *BMPTLV) DecodeFromBytes(data []byte) error { - //TODO: check data length - tlv.Type = binary.BigEndian.Uint16(data[0:2]) - tlv.Length = binary.BigEndian.Uint16(data[2:4]) - tlv.Value = data[4 : 4+tlv.Length] +func (s *BMPInfoTLVString) ParseValue(data []byte) error { + s.Value = string(data[:s.Length]) return nil } -func (tlv *BMPTLV) Serialize() ([]byte, error) { - if tlv.Length == 0 { - tlv.Length = uint16(len(tlv.Value)) - } - buf := make([]byte, 4+tlv.Length) - binary.BigEndian.PutUint16(buf[0:2], tlv.Type) - binary.BigEndian.PutUint16(buf[2:4], tlv.Length) - copy(buf[4:], tlv.Value) +func (s *BMPInfoTLVString) Serialize() ([]byte, error) { + s.Length = uint16(len([]byte(s.Value))) + buf := make([]byte, 4) + binary.BigEndian.PutUint16(buf[0:2], s.Type) + binary.BigEndian.PutUint16(buf[2:4], s.Length) + buf = append(buf, []byte(s.Value)...) return buf, nil } -func (tlv *BMPTLV) Len() int { - return 4 + int(tlv.Length) +type BMPInfoTLVUnknown struct { + BMPInfoTLV + Value []byte +} + +func NewBMPInfoTLVUnknown(t uint16, v []byte) *BMPInfoTLVUnknown { + return &BMPInfoTLVUnknown{ + BMPInfoTLV: BMPInfoTLV{Type: t}, + Value: v, + } +} + +func (s *BMPInfoTLVUnknown) ParseValue(data []byte) error { + s.Value = data[:s.Length] + return nil +} + +func (s *BMPInfoTLVUnknown) Serialize() ([]byte, error) { + s.Length = uint16(len([]byte(s.Value))) + buf := make([]byte, 4) + binary.BigEndian.PutUint16(buf[0:2], s.Type) + binary.BigEndian.PutUint16(buf[2:4], s.Length) + buf = append(buf, s.Value...) + return buf, nil } type BMPInitiation struct { - Info []BMPTLV + Info []BMPInfoTLVInterface } -func NewBMPInitiation(info []BMPTLV) *BMPMessage { +func NewBMPInitiation(info []BMPInfoTLVInterface) *BMPMessage { return &BMPMessage{ Header: BMPHeader{ Version: BMP_VERSION, @@ -583,11 +598,27 @@ func NewBMPInitiation(info []BMPTLV) *BMPMessage { } func (body *BMPInitiation) ParseBody(msg *BMPMessage, data []byte) error { - for len(data) > 0 { - tlv := BMPTLV{} - tlv.DecodeFromBytes(data) + for len(data) >= 4 { + tl := BMPInfoTLV{ + 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 tlv BMPInfoTLVInterface + switch tl.Type { + case BMP_INIT_TLV_TYPE_STRING, BMP_INIT_TLV_TYPE_SYS_DESCR, BMP_INIT_TLV_TYPE_SYS_NAME: + tlv = &BMPInfoTLVString{BMPInfoTLV: tl} + default: + tlv = &BMPInfoTLVUnknown{BMPInfoTLV: tl} + } + if err := tlv.ParseValue(data); err != nil { + return err + } body.Info = append(body.Info, tlv) - data = data[tlv.Len():] + data = data[tl.Length:] } return nil } @@ -604,6 +635,11 @@ func (body *BMPInitiation) Serialize() ([]byte, error) { return buf, nil } +const ( + BMP_TERM_TLV_TYPE_STRING = iota + BMP_TERM_TLV_TYPE_REASON +) + const ( BMP_TERM_REASON_ADMIN = iota BMP_TERM_REASON_UNSPEC @@ -650,6 +686,11 @@ func (body *BMPTermination) Serialize() ([]byte, error) { return buf, nil } +const ( + BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG = iota + BMP_ROUTE_MIRRORING_TLV_TYPE_INFO +) + const ( BMP_ROUTE_MIRRORING_INFO_ERR_PDU = iota BMP_ROUTE_MIRRORING_INFO_MSG_LOST diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go index 5e70710f..d2e07767 100644 --- a/packet/bmp/bmp_test.go +++ b/packet/bmp/bmp_test.go @@ -41,8 +41,10 @@ func verify(t *testing.T, m1 *BMPMessage) { func Test_Initiation(t *testing.T) { verify(t, NewBMPInitiation(nil)) - tlv := NewBMPTLV(1, []byte{0x3, 0xb, 0x0, 0x0, 0x0, 0xf, 0x42, 0x40}) - m := NewBMPInitiation([]BMPTLV{*tlv}) + m := NewBMPInitiation([]BMPInfoTLVInterface{ + NewBMPInfoTLVString(BMP_INIT_TLV_TYPE_STRING, "free-form UTF-8 string"), + NewBMPInfoTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}), + }) verify(t, m) } diff --git a/server/bmp.go b/server/bmp.go index 1d97104f..ec2c26ee 100644 --- a/server/bmp.go +++ b/server/bmp.go @@ -148,7 +148,7 @@ func (b *bmpClient) loop() { return err } - if err := write(bmp.NewBMPInitiation([]bmp.BMPTLV{})); err != nil { + if err := write(bmp.NewBMPInitiation([]bmp.BMPInfoTLVInterface{})); err != nil { return false }