diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2017-05-22 15:10:52 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-05-23 14:34:55 +0900 |
commit | 0ff4c8b20da26434f72bdb8597234704b8d8d5f8 (patch) | |
tree | 0c88fc39696f726f06bea567ec2094643a27994c | |
parent | d936841fb3238cc9ad0f728e1c929c8fad783290 (diff) |
bmp: Implement Information TLV on Termination messages
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
-rw-r--r-- | packet/bmp/bmp.go | 122 | ||||
-rw-r--r-- | packet/bmp/bmp_test.go | 10 | ||||
-rw-r--r-- | server/bmp.go | 6 |
3 files changed, 130 insertions, 8 deletions
diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go index e93ae61e..342c8e97 100644 --- a/packet/bmp/bmp.go +++ b/packet/bmp/bmp.go @@ -648,11 +648,99 @@ const ( BMP_TERM_REASON_PERMANENTLY_ADMIN ) +type BMPTermTLVInterface interface { + ParseValue([]byte) error + Serialize() ([]byte, error) +} + +type BMPTermTLV struct { + Type uint16 + Length uint16 +} + +type BMPTermTLVString struct { + BMPTermTLV + Value string +} + +func NewBMPTermTLVString(t uint16, v string) *BMPTermTLVString { + return &BMPTermTLVString{ + BMPTermTLV: BMPTermTLV{Type: t}, + Value: v, + } +} + +func (s *BMPTermTLVString) ParseValue(data []byte) error { + s.Value = string(data[:s.Length]) + return nil +} + +func (s *BMPTermTLVString) 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 +} + +type BMPTermTLV16 struct { + BMPTermTLV + Value uint16 +} + +func NewBMPTermTLV16(t uint16, v uint16) *BMPTermTLV16 { + return &BMPTermTLV16{ + BMPTermTLV: BMPTermTLV{Type: t}, + Value: v, + } +} + +func (s *BMPTermTLV16) ParseValue(data []byte) error { + s.Value = binary.BigEndian.Uint16(data[:2]) + return nil +} + +func (s *BMPTermTLV16) Serialize() ([]byte, error) { + s.Length = 2 + buf := make([]byte, 6) + binary.BigEndian.PutUint16(buf[0:2], s.Type) + binary.BigEndian.PutUint16(buf[2:4], s.Length) + binary.BigEndian.PutUint16(buf[4:6], s.Value) + return buf, nil +} + +type BMPTermTLVUnknown struct { + BMPTermTLV + Value []byte +} + +func NewBMPTermTLVUnknown(t uint16, v []byte) *BMPTermTLVUnknown { + return &BMPTermTLVUnknown{ + BMPTermTLV: BMPTermTLV{Type: t}, + Value: v, + } +} + +func (s *BMPTermTLVUnknown) ParseValue(data []byte) error { + s.Value = data[:s.Length] + return nil +} + +func (s *BMPTermTLVUnknown) 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 BMPTermination struct { - Info []BMPTLV + Info []BMPTermTLVInterface } -func NewBMPTermination(info []BMPTLV) *BMPMessage { +func NewBMPTermination(info []BMPTermTLVInterface) *BMPMessage { return &BMPMessage{ Header: BMPHeader{ Version: BMP_VERSION, @@ -665,11 +753,29 @@ func NewBMPTermination(info []BMPTLV) *BMPMessage { } func (body *BMPTermination) ParseBody(msg *BMPMessage, data []byte) error { - for len(data) > 0 { - tlv := BMPTLV{} - tlv.DecodeFromBytes(data) + for len(data) >= 4 { + tl := BMPTermTLV{ + 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 BMPTermTLVInterface + switch tl.Type { + case BMP_TERM_TLV_TYPE_STRING: + tlv = &BMPTermTLVString{BMPTermTLV: tl} + case BMP_TERM_TLV_TYPE_REASON: + tlv = &BMPTermTLV16{BMPTermTLV: tl} + default: + tlv = &BMPTermTLVUnknown{BMPTermTLV: 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 } @@ -712,7 +818,7 @@ type BMPMessage struct { func (msg *BMPMessage) Serialize() ([]byte, error) { buf := make([]byte, 0) - if msg.Header.Type != BMP_MSG_INITIATION { + if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION { p, err := msg.PeerHeader.Serialize() if err != nil { return nil, err @@ -780,7 +886,7 @@ func ParseBMPMessage(data []byte) (msg *BMPMessage, err error) { msg.Body = &BMPTermination{} } - if msg.Header.Type != BMP_MSG_INITIATION { + if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION { msg.PeerHeader.DecodeFromBytes(data) data = data[BMP_PEER_HEADER_SIZE:] } diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go index d2e07767..061e870c 100644 --- a/packet/bmp/bmp_test.go +++ b/packet/bmp/bmp_test.go @@ -48,6 +48,16 @@ func Test_Initiation(t *testing.T) { verify(t, m) } +func Test_Termination(t *testing.T) { + verify(t, NewBMPTermination(nil)) + m := NewBMPTermination([]BMPTermTLVInterface{ + NewBMPTermTLVString(BMP_TERM_TLV_TYPE_STRING, "free-form UTF-8 string"), + NewBMPTermTLV16(BMP_TERM_TLV_TYPE_REASON, BMP_TERM_REASON_ADMIN), + NewBMPTermTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}), + }) + verify(t, m) +} + func Test_PeerUpNotification(t *testing.T) { m := bgp.NewTestBGPOpenMessage() p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1) diff --git a/server/bmp.go b/server/bmp.go index ec2c26ee..e7dc3ea2 100644 --- a/server/bmp.go +++ b/server/bmp.go @@ -221,6 +221,12 @@ func (b *bmpClient) loop() { } } case <-b.dead: + term := bmp.NewBMPTermination([]bmp.BMPTermTLVInterface{ + bmp.NewBMPTermTLV16(bmp.BMP_TERM_TLV_TYPE_REASON, bmp.BMP_TERM_REASON_PERMANENTLY_ADMIN), + }) + if err := write(term); err != nil { + return false + } conn.Close() return true } |