summaryrefslogtreecommitdiffhomepage
path: root/packet/bmp
diff options
context:
space:
mode:
Diffstat (limited to 'packet/bmp')
-rw-r--r--packet/bmp/bmp.go157
-rw-r--r--packet/bmp/bmp_test.go14
2 files changed, 171 insertions, 0 deletions
diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go
index 342c8e97..6537e12c 100644
--- a/packet/bmp/bmp.go
+++ b/packet/bmp/bmp.go
@@ -802,6 +802,159 @@ const (
BMP_ROUTE_MIRRORING_INFO_MSG_LOST
)
+type BMPRouteMirrTLVInterface interface {
+ ParseValue([]byte) error
+ Serialize() ([]byte, error)
+}
+
+type BMPRouteMirrTLV struct {
+ Type uint16
+ Length uint16
+}
+
+type BMPRouteMirrTLVBGPMsg struct {
+ BMPRouteMirrTLV
+ Value *bgp.BGPMessage
+}
+
+func NewBMPRouteMirrTLVBGPMsg(t uint16, v *bgp.BGPMessage) *BMPRouteMirrTLVBGPMsg {
+ return &BMPRouteMirrTLVBGPMsg{
+ BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
+ Value: v,
+ }
+}
+
+func (s *BMPRouteMirrTLVBGPMsg) ParseValue(data []byte) error {
+ v, err := bgp.ParseBGPMessage(data)
+ if err != nil {
+ return err
+ }
+ s.Value = v
+ return nil
+}
+
+func (s *BMPRouteMirrTLVBGPMsg) Serialize() ([]byte, error) {
+ m, err := s.Value.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ s.Length = uint16(len(m))
+ buf := make([]byte, 4)
+ binary.BigEndian.PutUint16(buf[0:2], s.Type)
+ binary.BigEndian.PutUint16(buf[2:4], s.Length)
+ buf = append(buf, m...)
+ return buf, nil
+}
+
+type BMPRouteMirrTLV16 struct {
+ BMPRouteMirrTLV
+ Value uint16
+}
+
+func NewBMPRouteMirrTLV16(t uint16, v uint16) *BMPRouteMirrTLV16 {
+ return &BMPRouteMirrTLV16{
+ BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
+ Value: v,
+ }
+}
+
+func (s *BMPRouteMirrTLV16) ParseValue(data []byte) error {
+ s.Value = binary.BigEndian.Uint16(data[:2])
+ return nil
+}
+
+func (s *BMPRouteMirrTLV16) 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 BMPRouteMirrTLVUnknown struct {
+ BMPRouteMirrTLV
+ Value []byte
+}
+
+func NewBMPRouteMirrTLVUnknown(t uint16, v []byte) *BMPRouteMirrTLVUnknown {
+ return &BMPRouteMirrTLVUnknown{
+ BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
+ Value: v,
+ }
+}
+
+func (s *BMPRouteMirrTLVUnknown) ParseValue(data []byte) error {
+ s.Value = data[:s.Length]
+ return nil
+}
+
+func (s *BMPRouteMirrTLVUnknown) 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 BMPRouteMirroring struct {
+ Info []BMPRouteMirrTLVInterface
+}
+
+func NewBMPRouteMirroring(p BMPPeerHeader, info []BMPRouteMirrTLVInterface) *BMPMessage {
+ return &BMPMessage{
+ Header: BMPHeader{
+ Version: BMP_VERSION,
+ Type: BMP_MSG_ROUTE_MIRRORING,
+ },
+ PeerHeader: p,
+ Body: &BMPRouteMirroring{
+ Info: info,
+ },
+ }
+}
+
+func (body *BMPRouteMirroring) ParseBody(msg *BMPMessage, data []byte) error {
+ for len(data) >= 4 {
+ tl := BMPRouteMirrTLV{
+ 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 BMPRouteMirrTLVInterface
+ switch tl.Type {
+ case BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG:
+ tlv = &BMPRouteMirrTLVBGPMsg{BMPRouteMirrTLV: tl}
+ case BMP_ROUTE_MIRRORING_TLV_TYPE_INFO:
+ tlv = &BMPRouteMirrTLV16{BMPRouteMirrTLV: tl}
+ default:
+ tlv = &BMPRouteMirrTLVUnknown{BMPRouteMirrTLV: tl}
+ }
+ if err := tlv.ParseValue(data); err != nil {
+ return err
+ }
+ body.Info = append(body.Info, tlv)
+ data = data[tl.Length:]
+ }
+ return nil
+}
+
+func (body *BMPRouteMirroring) Serialize() ([]byte, error) {
+ buf := make([]byte, 0)
+ for _, tlv := range body.Info {
+ b, err := tlv.Serialize()
+ if err != nil {
+ return buf, err
+ }
+ buf = append(buf, b...)
+ }
+ return buf, nil
+}
+
type BMPBody interface {
// Sigh, some body messages need a BMPHeader to parse the body
// data so we need to pass BMPHeader (avoid DecodeFromBytes
@@ -884,6 +1037,10 @@ func ParseBMPMessage(data []byte) (msg *BMPMessage, err error) {
msg.Body = &BMPInitiation{}
case BMP_MSG_TERMINATION:
msg.Body = &BMPTermination{}
+ case BMP_MSG_ROUTE_MIRRORING:
+ msg.Body = &BMPRouteMirroring{}
+ default:
+ return nil, fmt.Errorf("unsupported BMP message type: %d", msg.Header.Type)
}
if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION {
diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go
index 061e870c..ecae38bc 100644
--- a/packet/bmp/bmp_test.go
+++ b/packet/bmp/bmp_test.go
@@ -92,6 +92,20 @@ func Test_StatisticsReport(t *testing.T) {
verify(t, s0)
}
+func Test_RouteMirroring(t *testing.T) {
+ p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
+ s0 := NewBMPRouteMirroring(
+ *p0,
+ []BMPRouteMirrTLVInterface{
+ NewBMPRouteMirrTLV16(BMP_ROUTE_MIRRORING_TLV_TYPE_INFO, BMP_ROUTE_MIRRORING_INFO_MSG_LOST),
+ NewBMPRouteMirrTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}),
+ // RFC7854: BGP Message TLV MUST occur last in the list of TLVs
+ NewBMPRouteMirrTLVBGPMsg(BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, bgp.NewTestBGPOpenMessage()),
+ },
+ )
+ verify(t, s0)
+}
+
func Test_BogusHeader(t *testing.T) {
h, err := ParseBMPMessage(make([]byte, 10))
assert.Nil(t, h)