Initial
This commit is contained in:
812
mrt/mrt.go
Normal file
812
mrt/mrt.go
Normal file
@@ -0,0 +1,812 @@
|
||||
package mrt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cloudflare/fgbgp/messages"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
TYPE_OSPFV2 = 11
|
||||
TYPE_TABLE_DUMP = 12
|
||||
TYPE_TABLE_DUMPV2 = 13
|
||||
|
||||
TYPE_BGP4MP = 16
|
||||
TYPE_BGP4MP_ET = 17
|
||||
|
||||
TYPE_ISIS = 32
|
||||
TYPE_ISIS_ET = 33
|
||||
|
||||
TYPE_OSPFV3 = 48
|
||||
TYPE_OSPFV3_ET = 49
|
||||
|
||||
SUBT_TABLE_DUMP_AFI_IPV4 = 1
|
||||
SUBT_TABLE_DUMP_AFI_IPV6 = 2
|
||||
|
||||
SUBT_TABLE_DUMPV2_PEER_INDEX_TABLE = 1
|
||||
SUBT_TABLE_DUMPV2_RIB_IPV4_UNICAST = 2
|
||||
SUBT_TABLE_DUMPV2_RIB_IPV4_MULTICAST = 3
|
||||
SUBT_TABLE_DUMPV2_RIB_IPV6_UNICAST = 4
|
||||
SUBT_TABLE_DUMPV2_RIB_IPV6_MULTICAST = 5
|
||||
SUBT_TABLE_DUMPV2_RIB_GENERIC = 6
|
||||
|
||||
SUBT_BGP4MP_STATE_CHANGE = 0
|
||||
SUBT_BGP4MP_MESSAGE = 1
|
||||
SUBT_BGP4MP_MESSAGE_AS4 = 4
|
||||
SUBT_BGP4MP_STATE_CHANGE_AS4 = 5
|
||||
SUBT_BGP4MP_MESSAGE_LOCAL = 6
|
||||
SUBT_BGP4MP_MESSAGE_AS4_LOCAL = 7
|
||||
|
||||
STATE_IDLE = 1
|
||||
STATE_CONNECT = 2
|
||||
STATE_ACTIVE = 3
|
||||
STATE_OPENSENT = 4
|
||||
STATE_OPENCONFIRM = 5
|
||||
STATE_ESTABLISHED = 6
|
||||
)
|
||||
|
||||
type Mrt interface {
|
||||
Write(io.Writer)
|
||||
Len() int
|
||||
}
|
||||
|
||||
func WriteCommonHeader(buf io.Writer, timestamp time.Time, mrttype uint16, subtype uint16, length uint32) {
|
||||
binary.Write(buf, binary.BigEndian, uint32(timestamp.Unix()))
|
||||
binary.Write(buf, binary.BigEndian, mrttype)
|
||||
binary.Write(buf, binary.BigEndian, subtype)
|
||||
binary.Write(buf, binary.BigEndian, length)
|
||||
}
|
||||
|
||||
type Peer struct {
|
||||
Id net.IP
|
||||
IP net.IP
|
||||
ASN uint32
|
||||
}
|
||||
|
||||
func (p *Peer) Write(buf io.Writer) {
|
||||
newip := p.IP
|
||||
firstbit := 1
|
||||
if tmpip := newip.To4(); tmpip != nil {
|
||||
newip = tmpip
|
||||
firstbit = 0
|
||||
}
|
||||
|
||||
longasn := 1
|
||||
if p.ASN <= 0xffff {
|
||||
longasn = 0
|
||||
}
|
||||
|
||||
firstbyte := byte(longasn<<2 | firstbit)
|
||||
binary.Write(buf, binary.BigEndian, firstbyte)
|
||||
|
||||
binary.Write(buf, binary.BigEndian, p.Id.To4())
|
||||
|
||||
binary.Write(buf, binary.BigEndian, newip)
|
||||
if longasn == 1 {
|
||||
binary.Write(buf, binary.BigEndian, p.ASN)
|
||||
} else {
|
||||
binary.Write(buf, binary.BigEndian, uint16(p.ASN))
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Peer) Len() int {
|
||||
iplen := 4
|
||||
newip := p.IP
|
||||
if tmpip := newip.To4(); tmpip == nil {
|
||||
iplen = 16
|
||||
}
|
||||
longasn := 4
|
||||
if p.ASN <= 0xffff {
|
||||
longasn = 2
|
||||
}
|
||||
return 1 + 4 + iplen + longasn
|
||||
}
|
||||
|
||||
type MrtTableDumpV2_PeerIndex struct {
|
||||
Timestamp time.Time
|
||||
CollectorId net.IP
|
||||
ViewName string
|
||||
Peers []*Peer
|
||||
}
|
||||
|
||||
func NewMrtTableDumpV2_PeerIndex(collectorid net.IP, viewname string, ts time.Time) *MrtTableDumpV2_PeerIndex {
|
||||
return &MrtTableDumpV2_PeerIndex{
|
||||
Timestamp: ts,
|
||||
CollectorId: collectorid,
|
||||
ViewName: viewname,
|
||||
Peers: make([]*Peer, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_PeerIndex) AddPeer(id net.IP, asn uint32, ip net.IP) uint16 {
|
||||
peer := &Peer{
|
||||
Id: id.To4(),
|
||||
IP: ip,
|
||||
ASN: asn,
|
||||
}
|
||||
mrt.Peers = append(mrt.Peers, peer)
|
||||
return uint16(len(mrt.Peers) - 1)
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_PeerIndex) Write(buf io.Writer) {
|
||||
WriteCommonHeader(buf, mrt.Timestamp, TYPE_TABLE_DUMPV2, SUBT_TABLE_DUMPV2_PEER_INDEX_TABLE, uint32(mrt.Len()))
|
||||
binary.Write(buf, binary.BigEndian, mrt.CollectorId.To4())
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(mrt.ViewName)))
|
||||
binary.Write(buf, binary.BigEndian, []byte(mrt.ViewName))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(mrt.Peers)))
|
||||
for i := range mrt.Peers {
|
||||
mrt.Peers[i].Write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_PeerIndex) Len() int {
|
||||
totallen := 4 + 2 + len(mrt.ViewName) + 2
|
||||
for i := range mrt.Peers {
|
||||
totallen += mrt.Peers[i].Len()
|
||||
}
|
||||
return totallen
|
||||
}
|
||||
|
||||
type RibEntry struct {
|
||||
PeerIndex uint16
|
||||
OrigTime time.Time
|
||||
Attributes []messages.BGPAttributeIf
|
||||
}
|
||||
|
||||
func (entry *RibEntry) Write(buf io.Writer) {
|
||||
binary.Write(buf, binary.BigEndian, entry.PeerIndex)
|
||||
binary.Write(buf, binary.BigEndian, uint32(entry.OrigTime.Unix()))
|
||||
|
||||
var size uint16
|
||||
|
||||
for i := range entry.Attributes {
|
||||
switch attribute := entry.Attributes[i].(type) {
|
||||
case *messages.BGPAttribute_MP_REACH:
|
||||
size += attribute.LenMrt()
|
||||
case *messages.BGPAttribute_MP_UNREACH:
|
||||
default:
|
||||
size += uint16(entry.Attributes[i].Len())
|
||||
}
|
||||
}
|
||||
|
||||
binary.Write(buf, binary.BigEndian, size)
|
||||
|
||||
for i := range entry.Attributes {
|
||||
switch attribute := entry.Attributes[i].(type) {
|
||||
case *messages.BGPAttribute_MP_REACH:
|
||||
attribute.WriteMrt(buf)
|
||||
case *messages.BGPAttribute_MP_UNREACH:
|
||||
default:
|
||||
entry.Attributes[i].Write(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (entry *RibEntry) Len() uint32 {
|
||||
size := uint32(2 + 4 + 2)
|
||||
// To optimize
|
||||
for i := range entry.Attributes {
|
||||
switch attribute := entry.Attributes[i].(type) {
|
||||
case *messages.BGPAttribute_MP_REACH:
|
||||
size += uint32(attribute.LenMrt())
|
||||
case *messages.BGPAttribute_MP_UNREACH:
|
||||
default:
|
||||
size += uint32(entry.Attributes[i].Len())
|
||||
}
|
||||
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
type MrtTableDumpV2_Rib struct {
|
||||
Timestamp time.Time
|
||||
SequenceNumber uint32
|
||||
Afi uint16
|
||||
Safi byte
|
||||
NLRI messages.NLRI
|
||||
RibEntries []*RibEntry
|
||||
|
||||
WriteAsAfiSafi bool
|
||||
}
|
||||
|
||||
func NewMrtTableDumpV2_RibGeneric(seqnum uint32, afi uint16, safi byte, nlri messages.NLRI, ts time.Time) *MrtTableDumpV2_Rib {
|
||||
return &MrtTableDumpV2_Rib{
|
||||
Timestamp: ts,
|
||||
SequenceNumber: seqnum,
|
||||
Afi: afi,
|
||||
Safi: safi,
|
||||
NLRI: nlri,
|
||||
RibEntries: make([]*RibEntry, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func NewMrtTableDumpV2_RibAfiSafi(seqnum uint32, afi uint16, safi byte, nlri messages.NLRI, ts time.Time) *MrtTableDumpV2_Rib {
|
||||
mrt := NewMrtTableDumpV2_RibGeneric(seqnum, afi, safi, nlri, ts)
|
||||
mrt.WriteAsAfiSafi = true
|
||||
return mrt
|
||||
}
|
||||
|
||||
func (entry *RibEntry) EntryToUpdate() *messages.BGPMessageUpdate {
|
||||
update := &messages.BGPMessageUpdate{
|
||||
PathAttributes: entry.Attributes,
|
||||
}
|
||||
return update
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_Rib) ConvertToUpdateIndex(index int) *messages.BGPMessageUpdate {
|
||||
re := mrt.RibEntries
|
||||
if index >= len(re) {
|
||||
return nil
|
||||
}
|
||||
entry := re[index]
|
||||
update := entry.EntryToUpdate()
|
||||
|
||||
if mrt.NLRI.GetAfi() == messages.AFI_IPV6 {
|
||||
pa := update.PathAttributes
|
||||
var hasreach bool
|
||||
for i := range pa {
|
||||
switch pai := pa[i].(type) {
|
||||
case messages.BGPAttribute_MP_REACH:
|
||||
// Check NLRI already in
|
||||
var hasipinreach bool
|
||||
hasreach = true
|
||||
|
||||
mpnlri := pai.NLRI
|
||||
for j := range mpnlri {
|
||||
if mrt.NLRI.Equals(mpnlri[j]) {
|
||||
hasipinreach = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasipinreach {
|
||||
pai.NLRI = append(pai.NLRI, mrt.NLRI)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if !hasreach {
|
||||
attr := &messages.BGPAttribute_MP_REACH{
|
||||
NLRI: []messages.NLRI{mrt.NLRI},
|
||||
}
|
||||
update.PathAttributes = append(update.PathAttributes, attr)
|
||||
}
|
||||
} else {
|
||||
update.NLRI = []messages.NLRI{mrt.NLRI}
|
||||
}
|
||||
return update
|
||||
}
|
||||
func (mrt *MrtTableDumpV2_Rib) ConvertToUpdate() []*messages.BGPMessageUpdate {
|
||||
updates := make([]*messages.BGPMessageUpdate, 0)
|
||||
re := mrt.RibEntries
|
||||
for i := range re {
|
||||
update := mrt.ConvertToUpdateIndex(i)
|
||||
if update != nil {
|
||||
updates = append(updates, update)
|
||||
}
|
||||
}
|
||||
return updates
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_Rib) AddEntry(peerindex uint16, origtime time.Time, attributes []messages.BGPAttributeIf) {
|
||||
entry := &RibEntry{
|
||||
PeerIndex: peerindex,
|
||||
OrigTime: origtime,
|
||||
Attributes: attributes,
|
||||
}
|
||||
mrt.RibEntries = append(mrt.RibEntries, entry)
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_Rib) GetSubtype() (bool, uint16) {
|
||||
subt := uint16(SUBT_TABLE_DUMPV2_RIB_GENERIC)
|
||||
force_generic := true
|
||||
|
||||
if mrt.WriteAsAfiSafi {
|
||||
if mrt.Afi == messages.AFI_IPV4 && mrt.Safi == messages.SAFI_UNICAST {
|
||||
force_generic = false
|
||||
subt = SUBT_TABLE_DUMPV2_RIB_IPV4_UNICAST
|
||||
} else if mrt.Afi == messages.AFI_IPV4 && mrt.Safi == messages.SAFI_MULTICAST {
|
||||
force_generic = false
|
||||
subt = SUBT_TABLE_DUMPV2_RIB_IPV4_MULTICAST
|
||||
} else if mrt.Afi == messages.AFI_IPV6 && mrt.Safi == messages.SAFI_UNICAST {
|
||||
force_generic = false
|
||||
subt = SUBT_TABLE_DUMPV2_RIB_IPV6_UNICAST
|
||||
} else if mrt.Afi == messages.AFI_IPV6 && mrt.Safi == messages.SAFI_MULTICAST {
|
||||
force_generic = false
|
||||
subt = SUBT_TABLE_DUMPV2_RIB_IPV6_MULTICAST
|
||||
}
|
||||
}
|
||||
return force_generic, subt
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_Rib) Write(buf io.Writer) {
|
||||
force_generic, subt := mrt.GetSubtype()
|
||||
|
||||
WriteCommonHeader(buf, mrt.Timestamp, TYPE_TABLE_DUMPV2, subt, uint32(mrt.Len()))
|
||||
if force_generic {
|
||||
binary.Write(buf, binary.BigEndian, mrt.Afi)
|
||||
binary.Write(buf, binary.BigEndian, mrt.Safi)
|
||||
}
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.SequenceNumber)
|
||||
binary.Write(buf, binary.BigEndian, mrt.NLRI.Bytes(false))
|
||||
binary.Write(buf, binary.BigEndian, uint16(len(mrt.RibEntries)))
|
||||
for i := range mrt.RibEntries {
|
||||
mrt.RibEntries[i].Write(buf)
|
||||
}
|
||||
}
|
||||
|
||||
func (mrt *MrtTableDumpV2_Rib) Len() int {
|
||||
force_generic, _ := mrt.GetSubtype()
|
||||
size := 4 + len(mrt.NLRI.Bytes(false)) + 2
|
||||
if force_generic {
|
||||
size += 2
|
||||
}
|
||||
for i := range mrt.RibEntries {
|
||||
size += int(mrt.RibEntries[i].Len())
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
type MrtBGP4MP_Msg_AS4 struct {
|
||||
Timestamp time.Time
|
||||
PeerAS uint32
|
||||
LocalAS uint32
|
||||
IfaceIndex uint16
|
||||
PeerIP net.IP
|
||||
LocalIP net.IP
|
||||
Message messages.SerializableInterface
|
||||
}
|
||||
|
||||
type MrtBGP4MP_StateChange_AS4 struct {
|
||||
Timestamp time.Time
|
||||
PeerAS uint32
|
||||
LocalAS uint32
|
||||
IfaceIndex uint16
|
||||
PeerIP net.IP
|
||||
LocalIP net.IP
|
||||
OldState uint16
|
||||
NewState uint16
|
||||
}
|
||||
|
||||
func NewMrtBGP4MP_StateChange_AS4(peeras uint32, localas uint32, iface uint16, peerip net.IP, localip net.IP, oldstate uint16, newstate uint16) *MrtBGP4MP_StateChange_AS4 {
|
||||
return &MrtBGP4MP_StateChange_AS4{
|
||||
Timestamp: time.Now().UTC(),
|
||||
PeerAS: peeras,
|
||||
LocalAS: localas,
|
||||
IfaceIndex: iface,
|
||||
PeerIP: peerip,
|
||||
LocalIP: localip,
|
||||
OldState: oldstate,
|
||||
NewState: newstate,
|
||||
}
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_StateChange_AS4) IsIPv4() bool {
|
||||
return mrt.PeerIP.To4() != nil
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_StateChange_AS4) Len() int {
|
||||
ipsize := 4
|
||||
if !mrt.IsIPv4() {
|
||||
ipsize = 16
|
||||
}
|
||||
return 4 + 4 + 2 + 2 + 2*ipsize + 2 + 2
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_StateChange_AS4) Write(buf io.Writer) {
|
||||
WriteCommonHeader(buf, mrt.Timestamp, TYPE_BGP4MP, SUBT_BGP4MP_STATE_CHANGE_AS4, uint32(mrt.Len()))
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerAS)
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalAS)
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.IfaceIndex)
|
||||
if mrt.IsIPv4() {
|
||||
binary.Write(buf, binary.BigEndian, uint16(messages.AFI_IPV4))
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerIP.To4())
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalIP.To4())
|
||||
} else {
|
||||
binary.Write(buf, binary.BigEndian, uint16(messages.AFI_IPV6))
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerIP)
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalIP)
|
||||
}
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.OldState)
|
||||
binary.Write(buf, binary.BigEndian, mrt.NewState)
|
||||
}
|
||||
|
||||
func NewMrtBGP4MP_Msg_AS4(peeras uint32, localas uint32, iface uint16, peerip net.IP, localip net.IP, message messages.SerializableInterface) *MrtBGP4MP_Msg_AS4 {
|
||||
return &MrtBGP4MP_Msg_AS4{
|
||||
Timestamp: time.Now().UTC(),
|
||||
PeerAS: peeras,
|
||||
LocalAS: localas,
|
||||
IfaceIndex: iface,
|
||||
PeerIP: peerip,
|
||||
LocalIP: localip,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_Msg_AS4) IsIPv4() bool {
|
||||
return mrt.PeerIP.To4() != nil
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_Msg_AS4) Len() int {
|
||||
ipsize := 4
|
||||
if !mrt.IsIPv4() {
|
||||
ipsize = 16
|
||||
}
|
||||
return 4 + 4 + 2 + 2 + 2*ipsize + mrt.Message.Len()
|
||||
}
|
||||
|
||||
func (mrt *MrtBGP4MP_Msg_AS4) Write(buf io.Writer) {
|
||||
WriteCommonHeader(buf, mrt.Timestamp, TYPE_BGP4MP, SUBT_BGP4MP_MESSAGE_AS4, uint32(mrt.Len()))
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerAS)
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalAS)
|
||||
|
||||
binary.Write(buf, binary.BigEndian, mrt.IfaceIndex)
|
||||
if mrt.IsIPv4() {
|
||||
binary.Write(buf, binary.BigEndian, uint16(messages.AFI_IPV4))
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerIP.To4())
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalIP.To4())
|
||||
} else {
|
||||
binary.Write(buf, binary.BigEndian, uint16(messages.AFI_IPV6))
|
||||
binary.Write(buf, binary.BigEndian, mrt.PeerIP)
|
||||
binary.Write(buf, binary.BigEndian, mrt.LocalIP)
|
||||
}
|
||||
mrt.Message.Write(buf)
|
||||
}
|
||||
|
||||
func DecodeBGP4MP(buf io.Reader, timestamp time.Time, subtype uint16, length uint32) (Mrt, error) {
|
||||
switch subtype {
|
||||
case SUBT_BGP4MP_MESSAGE_AS4:
|
||||
var peeras uint32
|
||||
var localas uint32
|
||||
var ifaceindex uint16
|
||||
var afi uint16
|
||||
binary.Read(buf, binary.BigEndian, peeras)
|
||||
binary.Read(buf, binary.BigEndian, localas)
|
||||
binary.Read(buf, binary.BigEndian, ifaceindex)
|
||||
binary.Read(buf, binary.BigEndian, afi)
|
||||
var peerip []byte
|
||||
var localip []byte
|
||||
sizeip := 4
|
||||
if afi == messages.AFI_IPV6 {
|
||||
sizeip = 16
|
||||
}
|
||||
peerip = make([]byte, sizeip)
|
||||
localip = make([]byte, sizeip)
|
||||
binary.Read(buf, binary.BigEndian, peerip)
|
||||
binary.Read(buf, binary.BigEndian, localip)
|
||||
|
||||
msgsize := length - uint32(4+4+2+2+2*(sizeip))
|
||||
if msgsize < 0 {
|
||||
return nil, errors.New("DecodeBGP4MP: cannot decode message with negative length")
|
||||
}
|
||||
msg := make([]byte, msgsize)
|
||||
// Do progressive read or replace parsepacketheader with io.Reader
|
||||
binary.Read(buf, binary.BigEndian, msg)
|
||||
|
||||
bgptype, bgplen, err1 := messages.ParsePacketHeader(msg)
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
pktd, err2 := messages.ParsePacket(bgptype, msg[19:19+bgplen])
|
||||
|
||||
mrt := &MrtBGP4MP_Msg_AS4{
|
||||
Timestamp: timestamp,
|
||||
PeerAS: peeras,
|
||||
LocalAS: localas,
|
||||
IfaceIndex: ifaceindex,
|
||||
PeerIP: net.IP(peerip),
|
||||
LocalIP: net.IP(localip),
|
||||
Message: pktd,
|
||||
}
|
||||
|
||||
return mrt, err2
|
||||
case SUBT_BGP4MP_STATE_CHANGE_AS4:
|
||||
var peeras uint32
|
||||
var localas uint32
|
||||
var ifaceindex uint16
|
||||
var afi uint16
|
||||
binary.Read(buf, binary.BigEndian, peeras)
|
||||
binary.Read(buf, binary.BigEndian, localas)
|
||||
binary.Read(buf, binary.BigEndian, ifaceindex)
|
||||
binary.Read(buf, binary.BigEndian, afi)
|
||||
var peerip []byte
|
||||
var localip []byte
|
||||
sizeip := 4
|
||||
if afi == messages.AFI_IPV6 {
|
||||
sizeip = 16
|
||||
}
|
||||
peerip = make([]byte, sizeip)
|
||||
localip = make([]byte, sizeip)
|
||||
binary.Read(buf, binary.BigEndian, peerip)
|
||||
binary.Read(buf, binary.BigEndian, localip)
|
||||
var oldstate uint16
|
||||
var newstate uint16
|
||||
binary.Read(buf, binary.BigEndian, oldstate)
|
||||
binary.Read(buf, binary.BigEndian, newstate)
|
||||
|
||||
mrt := &MrtBGP4MP_StateChange_AS4{
|
||||
Timestamp: timestamp,
|
||||
PeerAS: peeras,
|
||||
LocalAS: localas,
|
||||
IfaceIndex: ifaceindex,
|
||||
PeerIP: net.IP(peerip),
|
||||
LocalIP: net.IP(localip),
|
||||
OldState: oldstate,
|
||||
NewState: newstate,
|
||||
}
|
||||
|
||||
return mrt, nil
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("Decoding of subtype %v of BGP4MP not implemented", subtype))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DecodeNLRI(buf io.Reader, afi uint16, safi byte) (messages.NLRI, error) {
|
||||
if afi != messages.AFI_IPV4 && afi != messages.AFI_IPV6 {
|
||||
return nil, errors.New(fmt.Sprintf("Could not decode NLRI for Afi: %v", afi))
|
||||
}
|
||||
if safi != messages.SAFI_UNICAST && safi != messages.SAFI_MULTICAST {
|
||||
return nil, errors.New(fmt.Sprintf("Could not decode NLRI for Safi: %v", safi))
|
||||
}
|
||||
|
||||
var l byte
|
||||
binary.Read(buf, binary.BigEndian, &l)
|
||||
|
||||
size := l / 8
|
||||
if l%8 != 0 {
|
||||
size++
|
||||
}
|
||||
b := make([]byte, size)
|
||||
binary.Read(buf, binary.BigEndian, &b)
|
||||
|
||||
newb := append([]byte{l}, b...)
|
||||
nlri, err := messages.ParseNLRI(newb, afi, safi, false)
|
||||
|
||||
if len(nlri) == 1 {
|
||||
return nlri[0], err
|
||||
} else {
|
||||
return nil, errors.New(fmt.Sprintf("Could not decode NLRI %v (%v/%v) (number of results != 1): %v", newb, afi, safi, err))
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeAttributes(buf io.Reader, attrlen uint16) ([]messages.BGPAttributeIf, error) {
|
||||
b := make([]byte, attrlen)
|
||||
binary.Read(buf, binary.BigEndian, b)
|
||||
return messages.ParsePathAttribute(b, nil, false)
|
||||
}
|
||||
|
||||
func DecodeRibEntries(buf io.Reader) (*RibEntry, error) {
|
||||
var peerindex uint16
|
||||
var origints uint32
|
||||
var attrlen uint16
|
||||
binary.Read(buf, binary.BigEndian, &peerindex)
|
||||
binary.Read(buf, binary.BigEndian, &origints)
|
||||
binary.Read(buf, binary.BigEndian, &attrlen)
|
||||
attrs, err := DecodeAttributes(buf, attrlen)
|
||||
origintsP := time.Unix(int64(origints), 0)
|
||||
re := &RibEntry{
|
||||
OrigTime: origintsP,
|
||||
PeerIndex: peerindex,
|
||||
Attributes: attrs,
|
||||
}
|
||||
return re, err
|
||||
}
|
||||
|
||||
func DecodeBGP4TD2RIBSpec(buf io.Reader, subtype uint16, timestamp time.Time) (Mrt, error) {
|
||||
var afi uint16
|
||||
var safi byte
|
||||
if subtype == SUBT_TABLE_DUMPV2_RIB_IPV4_UNICAST {
|
||||
afi = messages.AFI_IPV4
|
||||
safi = messages.SAFI_UNICAST
|
||||
} else if subtype == SUBT_TABLE_DUMPV2_RIB_IPV6_UNICAST {
|
||||
afi = messages.AFI_IPV6
|
||||
safi = messages.SAFI_UNICAST
|
||||
} else if subtype == SUBT_TABLE_DUMPV2_RIB_IPV4_MULTICAST {
|
||||
afi = messages.AFI_IPV4
|
||||
safi = messages.SAFI_MULTICAST
|
||||
} else if subtype == SUBT_TABLE_DUMPV2_RIB_IPV6_MULTICAST {
|
||||
afi = messages.AFI_IPV6
|
||||
safi = messages.SAFI_MULTICAST
|
||||
} else {
|
||||
return nil, errors.New("Cannot decode as Rib Afi/Safi specific")
|
||||
}
|
||||
|
||||
var seqnum uint32
|
||||
var preflen uint8
|
||||
var prefix []byte
|
||||
binary.Read(buf, binary.BigEndian, &seqnum)
|
||||
binary.Read(buf, binary.BigEndian, &preflen)
|
||||
|
||||
size := preflen / 8
|
||||
if preflen%8 != 0 {
|
||||
size++
|
||||
}
|
||||
prefix = make([]byte, size)
|
||||
binary.Read(buf, binary.BigEndian, &prefix)
|
||||
|
||||
newb := append([]byte{preflen}, prefix...)
|
||||
nlri, err := messages.ParseNLRI(newb, afi, safi, false)
|
||||
|
||||
mrt := &MrtTableDumpV2_Rib{
|
||||
Timestamp: timestamp,
|
||||
Afi: afi,
|
||||
Safi: safi,
|
||||
SequenceNumber: seqnum,
|
||||
WriteAsAfiSafi: true,
|
||||
}
|
||||
|
||||
if len(nlri) == 1 {
|
||||
mrt.NLRI = nlri[0]
|
||||
} else {
|
||||
return mrt, errors.New(fmt.Sprintf("Could not decode NLRI %v (%v/%v) (number of results != 1): %v", newb, afi, safi, err))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return mrt, err
|
||||
}
|
||||
|
||||
var entrycount uint16
|
||||
binary.Read(buf, binary.BigEndian, &entrycount)
|
||||
entries := make([]*RibEntry, entrycount)
|
||||
var errentry error
|
||||
for i := 0; i < int(entrycount); i++ {
|
||||
var entry *RibEntry
|
||||
entry, errentry = DecodeRibEntries(buf)
|
||||
entries[i] = entry
|
||||
}
|
||||
mrt.RibEntries = entries
|
||||
return mrt, errentry
|
||||
}
|
||||
|
||||
func DecodeBGP4TD2(buf io.Reader, timestamp time.Time, subtype uint16, length uint32) (Mrt, error) {
|
||||
switch subtype {
|
||||
case SUBT_TABLE_DUMPV2_PEER_INDEX_TABLE:
|
||||
collid := make([]byte, 4)
|
||||
var viewnamelen uint16
|
||||
var peercount uint16
|
||||
var viewname []byte
|
||||
var peers []*Peer
|
||||
|
||||
binary.Read(buf, binary.BigEndian, &collid)
|
||||
binary.Read(buf, binary.BigEndian, &viewnamelen)
|
||||
|
||||
viewname = make([]byte, viewnamelen)
|
||||
|
||||
binary.Read(buf, binary.BigEndian, &viewname)
|
||||
binary.Read(buf, binary.BigEndian, &peercount)
|
||||
|
||||
peers = make([]*Peer, peercount)
|
||||
|
||||
for i := 0; i < int(peercount); i++ {
|
||||
var peertype uint8
|
||||
bgpid := make([]byte, 4)
|
||||
var asn uint32
|
||||
var peerip []byte
|
||||
|
||||
binary.Read(buf, binary.BigEndian, &peertype)
|
||||
binary.Read(buf, binary.BigEndian, &bgpid)
|
||||
|
||||
sizeip := 4
|
||||
sizeasn := 2
|
||||
if peertype&0x2 != 0 {
|
||||
sizeasn = 4
|
||||
}
|
||||
if peertype&0x1 != 0 {
|
||||
sizeip = 16
|
||||
}
|
||||
tmpasn := make([]byte, sizeasn)
|
||||
peerip = make([]byte, sizeip)
|
||||
|
||||
binary.Read(buf, binary.BigEndian, &peerip)
|
||||
binary.Read(buf, binary.BigEndian, &tmpasn)
|
||||
|
||||
if sizeasn == 2 {
|
||||
asn = uint32(binary.BigEndian.Uint16(tmpasn))
|
||||
} else if sizeasn == 4 {
|
||||
asn = binary.BigEndian.Uint32(tmpasn)
|
||||
}
|
||||
|
||||
curpeer := &Peer{
|
||||
Id: bgpid,
|
||||
IP: peerip,
|
||||
ASN: asn,
|
||||
}
|
||||
|
||||
peers[i] = curpeer
|
||||
}
|
||||
|
||||
mrt := &MrtTableDumpV2_PeerIndex{
|
||||
Timestamp: timestamp,
|
||||
CollectorId: collid,
|
||||
ViewName: string(viewname),
|
||||
Peers: peers,
|
||||
}
|
||||
return mrt, nil
|
||||
|
||||
case SUBT_TABLE_DUMPV2_RIB_GENERIC:
|
||||
var seqnum uint32
|
||||
var afi uint16
|
||||
var safi byte
|
||||
binary.Read(buf, binary.BigEndian, &seqnum)
|
||||
binary.Read(buf, binary.BigEndian, &afi)
|
||||
binary.Read(buf, binary.BigEndian, &safi)
|
||||
|
||||
nlri, err := DecodeNLRI(buf, afi, safi)
|
||||
|
||||
mrt := &MrtTableDumpV2_Rib{
|
||||
Timestamp: timestamp,
|
||||
Afi: afi,
|
||||
Safi: safi,
|
||||
SequenceNumber: seqnum,
|
||||
NLRI: nlri,
|
||||
}
|
||||
if err != nil {
|
||||
return mrt, err
|
||||
}
|
||||
|
||||
var entrycount uint16
|
||||
binary.Read(buf, binary.BigEndian, &entrycount)
|
||||
entries := make([]*RibEntry, entrycount)
|
||||
var errentry error
|
||||
for i := 0; i < int(entrycount); i++ {
|
||||
var entry *RibEntry
|
||||
entry, errentry = DecodeRibEntries(buf)
|
||||
entries[i] = entry
|
||||
}
|
||||
mrt.RibEntries = entries
|
||||
return mrt, errentry
|
||||
case SUBT_TABLE_DUMPV2_RIB_IPV4_UNICAST:
|
||||
return DecodeBGP4TD2RIBSpec(buf, subtype, timestamp)
|
||||
case SUBT_TABLE_DUMPV2_RIB_IPV6_UNICAST:
|
||||
return DecodeBGP4TD2RIBSpec(buf, subtype, timestamp)
|
||||
case SUBT_TABLE_DUMPV2_RIB_IPV4_MULTICAST:
|
||||
return DecodeBGP4TD2RIBSpec(buf, subtype, timestamp)
|
||||
case SUBT_TABLE_DUMPV2_RIB_IPV6_MULTICAST:
|
||||
return DecodeBGP4TD2RIBSpec(buf, subtype, timestamp)
|
||||
default:
|
||||
return nil, errors.New(fmt.Sprintf("Decoding of subtype %v of BGP4TableDumpV2 not implemented", subtype))
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DecodeSingle(buf io.Reader) (Mrt, error) {
|
||||
var timestamp uint32
|
||||
var mrttype uint16
|
||||
var mrtsubtype uint16
|
||||
var mrtlength uint32
|
||||
|
||||
binary.Read(buf, binary.BigEndian, ×tamp)
|
||||
binary.Read(buf, binary.BigEndian, &mrttype)
|
||||
binary.Read(buf, binary.BigEndian, &mrtsubtype)
|
||||
binary.Read(buf, binary.BigEndian, &mrtlength)
|
||||
|
||||
timestampP := time.Unix(int64(timestamp), 0)
|
||||
|
||||
content := make([]byte, mrtlength)
|
||||
binary.Read(buf, binary.BigEndian, &content)
|
||||
tmpbuf := bytes.NewBuffer(content)
|
||||
|
||||
var mrt Mrt
|
||||
var err error
|
||||
switch mrttype {
|
||||
case TYPE_BGP4MP:
|
||||
mrt, err = DecodeBGP4MP(tmpbuf, timestampP, mrtsubtype, mrtlength)
|
||||
case TYPE_TABLE_DUMPV2:
|
||||
mrt, err = DecodeBGP4TD2(tmpbuf, timestampP, mrtsubtype, mrtlength)
|
||||
default:
|
||||
err = errors.New(fmt.Sprintf("Decoding of type %v not implemented", mrttype))
|
||||
}
|
||||
|
||||
return mrt, err
|
||||
}
|
||||
Reference in New Issue
Block a user