Files
fgbgp/mrt/mrt.go
2018-03-23 18:59:10 +01:00

813 lines
21 KiB
Go

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, &timestamp)
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
}