summaryrefslogtreecommitdiffhomepage
path: root/packet/bmp.go
diff options
context:
space:
mode:
Diffstat (limited to 'packet/bmp.go')
-rw-r--r--packet/bmp.go371
1 files changed, 371 insertions, 0 deletions
diff --git a/packet/bmp.go b/packet/bmp.go
new file mode 100644
index 00000000..d7758120
--- /dev/null
+++ b/packet/bmp.go
@@ -0,0 +1,371 @@
+// Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bgp
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math"
+ "net"
+)
+
+type BMPHeader struct {
+ Version uint8
+ Length uint32
+ Type uint8
+}
+
+const (
+ BMP_HEADER_SIZE = 6
+)
+
+func (msg *BMPHeader) DecodeFromBytes(data []byte) error {
+ msg.Version = data[0]
+ if data[0] != 3 {
+ return fmt.Errorf("error version")
+ }
+ msg.Length = binary.BigEndian.Uint32(data[1:5])
+ msg.Type = data[5]
+ return nil
+}
+
+func (msg *BMPHeader) Len() int {
+ return int(msg.Length)
+}
+
+type BMPPeerHeader struct {
+ PeerType uint8
+ IsPostPolicy bool
+ PeerDistinguisher uint64
+ PeerAddress net.IP
+ PeerAS uint32
+ PeerBGPID net.IP
+ Timestamp float64
+ flags uint8
+}
+
+func (msg *BMPPeerHeader) DecodeFromBytes(data []byte) error {
+ data = data[6:]
+
+ msg.PeerType = data[0]
+ flags := data[1]
+ msg.flags = flags
+ if flags&1<<6 == 1 {
+ msg.IsPostPolicy = true
+ } else {
+ msg.IsPostPolicy = false
+ }
+ msg.PeerDistinguisher = binary.BigEndian.Uint64(data[2:10])
+ if flags&1<<7 == 1 {
+ msg.PeerAddress = data[10:26]
+ } else {
+ msg.PeerAddress = data[10:14]
+ }
+ msg.PeerAS = binary.BigEndian.Uint32(data[26:30])
+ msg.PeerBGPID = data[30:34]
+
+ timestamp1 := binary.BigEndian.Uint32(data[34:38])
+ timestamp2 := binary.BigEndian.Uint32(data[38:42])
+ msg.Timestamp = float64(timestamp1) + float64(timestamp2)*math.Pow(10, -6)
+
+ return nil
+}
+
+type BMPRouteMonitoring struct {
+ BGPUpdate *BGPMessage
+}
+
+func (body *BMPRouteMonitoring) ParseBody(msg *BMPMessage, data []byte) error {
+ update, err := ParseBGPMessage(data)
+ if err != nil {
+ return err
+ }
+ body.BGPUpdate = update
+ return nil
+}
+
+const (
+ BMP_STAT_TYPE_REJECTED = iota
+ BMP_STAT_TYPE_DUPLICATE_PREFIX
+ BMP_STAT_TYPE_DUPLICATE_WITHDRAW
+ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP
+ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP
+ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID
+ BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP
+ BMP_STAT_TYPE_ADJ_RIB_IN
+ BMP_STAT_TYPE_LOC_RIB
+)
+
+type BMPStatsTLV struct {
+ Type uint16
+ Length uint16
+ Value uint64
+}
+
+type BMPStatisticsReport struct {
+ Stats []BMPStatsTLV
+}
+
+const (
+ BMP_PEER_DOWN_REASON_UNKNOWN = iota
+ BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION
+ BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION
+ BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION
+ BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION
+)
+
+type BMPPeerDownNotification struct {
+ Reason uint8
+ BGPNotification *BGPMessage
+ Data []byte
+}
+
+func (body *BMPPeerDownNotification) ParseBody(msg *BMPMessage, data []byte) error {
+ body.Reason = data[0]
+ data = data[1:]
+ if body.Reason == BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION || body.Reason == BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION {
+ notification, err := ParseBGPMessage(data)
+ if err != nil {
+ return err
+ }
+ body.BGPNotification = notification
+ } else {
+ body.Data = data
+ }
+ return nil
+}
+
+type BMPPeerUpNotification struct {
+ LocalAddress net.IP
+ LocalPort uint16
+ RemotePort uint16
+ SentOpenMsg *BGPMessage
+ ReceivedOpenMsg *BGPMessage
+}
+
+func (body *BMPPeerUpNotification) ParseBody(msg *BMPMessage, data []byte) error {
+ if msg.PeerHeader.flags&1<<7 == 1 {
+ body.LocalAddress = data[:16]
+ } else {
+ body.LocalAddress = data[:4]
+ }
+
+ body.LocalPort = binary.BigEndian.Uint16(data[16:18])
+ body.RemotePort = binary.BigEndian.Uint16(data[18:20])
+
+ data = data[20:]
+ sentopen, err := ParseBGPMessage(data)
+ if err != nil {
+ return err
+ }
+ body.SentOpenMsg = sentopen
+ data = data[body.SentOpenMsg.Header.Len:]
+ body.ReceivedOpenMsg, err = ParseBGPMessage(data)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (body *BMPStatisticsReport) ParseBody(msg *BMPMessage, data []byte) error {
+ _ = 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])
+
+ if s.Type == BMP_STAT_TYPE_ADJ_RIB_IN || s.Type == BMP_STAT_TYPE_LOC_RIB {
+ s.Value = binary.BigEndian.Uint64(data[4:12])
+ } else {
+ s.Value = uint64(binary.BigEndian.Uint32(data[4:8]))
+ }
+ body.Stats = append(body.Stats, s)
+ data = data[4+s.Length:]
+ }
+ return nil
+}
+
+type BMPTLV struct {
+ Type uint16
+ Length uint16
+ Value []byte
+}
+
+type BMPInitiation struct {
+ Info []BMPTLV
+}
+
+func (body *BMPInitiation) ParseBody(msg *BMPMessage, data []byte) error {
+ for len(data) >= 4 {
+ tlv := BMPTLV{}
+ tlv.Type = binary.BigEndian.Uint16(data[0:2])
+ tlv.Length = binary.BigEndian.Uint16(data[2:4])
+ tlv.Value = data[4 : 4+tlv.Length]
+
+ body.Info = append(body.Info, tlv)
+ data = data[4+tlv.Length:]
+ }
+ return nil
+}
+
+type BMPTermination struct {
+ Info []BMPTLV
+}
+
+func (body *BMPTermination) ParseBody(msg *BMPMessage, data []byte) error {
+ for len(data) >= 4 {
+ tlv := BMPTLV{}
+ tlv.Type = binary.BigEndian.Uint16(data[0:2])
+ tlv.Length = binary.BigEndian.Uint16(data[2:4])
+ tlv.Value = data[4 : 4+tlv.Length]
+
+ body.Info = append(body.Info, tlv)
+ data = data[4+tlv.Length:]
+ }
+ return nil
+}
+
+type BMPBody interface {
+ ParseBody(*BMPMessage, []byte) error
+}
+
+type BMPMessage struct {
+ Header BMPHeader
+ PeerHeader BMPPeerHeader
+ Body BMPBody
+}
+
+func (msg *BMPMessage) Len() int {
+ return int(msg.Header.Length)
+}
+
+const (
+ BMP_MSG_ROUTE_MONITORING = iota
+ BMP_MSG_STATISTICS_REPORT
+ BMP_MSG_PEER_DOWN_NOTIFICATION
+ BMP_MSG_PEER_UP_NOTIFICATION
+ BMP_MSG_INITIATION
+ BMP_MSG_TERMINATION
+)
+
+// move somewhere else
+func ReadBMPMessage(conn net.Conn) (*BMPMessage, error) {
+ buf := make([]byte, BMP_HEADER_SIZE)
+ for offset := 0; offset < BMP_HEADER_SIZE; {
+ rlen, err := conn.Read(buf[offset:])
+ if err != nil {
+ return nil, err
+ }
+ offset += rlen
+ }
+
+ h := BMPHeader{}
+ err := h.DecodeFromBytes(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ data := make([]byte, h.Len())
+ copy(data, buf)
+ data = data[BMP_HEADER_SIZE:]
+ for offset := 0; offset < h.Len()-BMP_HEADER_SIZE; {
+ rlen, err := conn.Read(data[offset:])
+ if err != nil {
+ return nil, err
+ }
+ offset += rlen
+ }
+ msg := &BMPMessage{Header: h}
+
+ switch msg.Header.Type {
+ case BMP_MSG_ROUTE_MONITORING:
+ msg.Body = &BMPRouteMonitoring{}
+ case BMP_MSG_STATISTICS_REPORT:
+ msg.Body = &BMPStatisticsReport{}
+ case BMP_MSG_PEER_DOWN_NOTIFICATION:
+ msg.Body = &BMPPeerDownNotification{}
+ case BMP_MSG_PEER_UP_NOTIFICATION:
+ msg.Body = &BMPPeerUpNotification{}
+ case BMP_MSG_INITIATION:
+ msg.Body = &BMPInitiation{}
+ case BMP_MSG_TERMINATION:
+ msg.Body = &BMPTermination{}
+ }
+
+ if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_INITIATION {
+ msg.PeerHeader.DecodeFromBytes(data)
+ data = data[42:]
+ }
+
+ err = msg.Body.ParseBody(msg, data)
+ if err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+func ParseBMPMessage(data []byte) (*BMPMessage, error) {
+ msg := &BMPMessage{}
+ msg.Header.DecodeFromBytes(data)
+ data = data[6:msg.Header.Length]
+
+ switch msg.Header.Type {
+ case BMP_MSG_ROUTE_MONITORING:
+ msg.Body = &BMPRouteMonitoring{}
+ case BMP_MSG_STATISTICS_REPORT:
+ msg.Body = &BMPStatisticsReport{}
+ case BMP_MSG_PEER_DOWN_NOTIFICATION:
+ msg.Body = &BMPPeerDownNotification{}
+ case BMP_MSG_PEER_UP_NOTIFICATION:
+ msg.Body = &BMPPeerUpNotification{}
+ case BMP_MSG_INITIATION:
+ msg.Body = &BMPInitiation{}
+ case BMP_MSG_TERMINATION:
+ msg.Body = &BMPTermination{}
+ }
+
+ if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_INITIATION {
+ msg.PeerHeader.DecodeFromBytes(data)
+ data = data[42:]
+ }
+
+ err := msg.Body.ParseBody(msg, data)
+ if err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
+
+type MessageError struct {
+ TypeCode uint8
+ SubTypeCode uint8
+ Data []byte
+ Message string
+}
+
+func NewMessageError(typeCode, subTypeCode uint8, data []byte, msg string) error {
+ return &MessageError{
+ TypeCode: typeCode,
+ SubTypeCode: subTypeCode,
+ Data: data,
+ Message: msg,
+ }
+}
+
+func (e *MessageError) Error() string {
+ return e.Message
+}