summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-05-22 15:10:52 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-05-23 14:34:55 +0900
commit0ff4c8b20da26434f72bdb8597234704b8d8d5f8 (patch)
tree0c88fc39696f726f06bea567ec2094643a27994c
parentd936841fb3238cc9ad0f728e1c929c8fad783290 (diff)
bmp: Implement Information TLV on Termination messages
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
-rw-r--r--packet/bmp/bmp.go122
-rw-r--r--packet/bmp/bmp_test.go10
-rw-r--r--server/bmp.go6
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
}