summaryrefslogtreecommitdiffhomepage
path: root/packet
diff options
context:
space:
mode:
Diffstat (limited to 'packet')
-rw-r--r--packet/mrt.go732
-rw-r--r--packet/mrt_test.go183
2 files changed, 915 insertions, 0 deletions
diff --git a/packet/mrt.go b/packet/mrt.go
new file mode 100644
index 00000000..f31013ec
--- /dev/null
+++ b/packet/mrt.go
@@ -0,0 +1,732 @@
+// Copyright (C) 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 (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math"
+ "net"
+)
+
+const (
+ MRT_COMMON_HEADER_LEN = 12
+)
+
+type MRTType uint16
+
+const (
+ NULL MRTType = 0 // deprecated
+ START MRTType = 1 // deprecated
+ DIE MRTType = 2 // deprecated
+ I_AM_DEAD MRTType = 3 // deprecated
+ PEER_DOWN MRTType = 4 // deprecated
+ BGP MRTType = 5 // deprecated
+ RIP MRTType = 6 // deprecated
+ IDRP MRTType = 7 // deprecated
+ RIPNG MRTType = 8 // deprecated
+ BGP4PLUS MRTType = 9 // deprecated
+ BGP4PLUS01 MRTType = 10 // deprecated
+ OSPFv2 MRTType = 11
+ TABLE_DUMP MRTType = 12
+ TABLE_DUMPv2 MRTType = 13
+ BGP4MP MRTType = 16
+ BGP4MP_ET MRTType = 17
+ ISIS MRTType = 32
+ ISIS_ET MRTType = 33
+ OSPFv3 MRTType = 48
+ OSPFv3_ET MRTType = 49
+)
+
+type MRTSubTyper interface {
+ ToUint16() uint16
+}
+
+type MRTSubTypeTableDumpv2 uint16
+
+const (
+ PEER_INDEX_TABLE MRTSubTypeTableDumpv2 = 1
+ RIB_IPV4_UNICAST MRTSubTypeTableDumpv2 = 2
+ RIB_IPV4_MULTICAST MRTSubTypeTableDumpv2 = 3
+ RIB_IPV6_UNICAST MRTSubTypeTableDumpv2 = 4
+ RIB_IPV6_MULTICAST MRTSubTypeTableDumpv2 = 5
+ RIB_GENERIC MRTSubTypeTableDumpv2 = 6
+)
+
+func (t MRTSubTypeTableDumpv2) ToUint16() uint16 {
+ return uint16(t)
+}
+
+type MRTSubTypeBGP4MP uint16
+
+const (
+ STATE_CHANGE MRTSubTypeBGP4MP = 0
+ MESSAGE MRTSubTypeBGP4MP = 1
+ MESSAGE_AS4 MRTSubTypeBGP4MP = 4
+ STATE_CHANGE_AS4 MRTSubTypeBGP4MP = 5
+ MESSAGE_LOCAL MRTSubTypeBGP4MP = 6
+ MESSAGE_AS4_LOCAL MRTSubTypeBGP4MP = 7
+)
+
+func (t MRTSubTypeBGP4MP) ToUint16() uint16 {
+ return uint16(t)
+}
+
+type BGPState uint16
+
+const (
+ IDLE BGPState = 1
+ CONNECT BGPState = 2
+ ACTIVE BGPState = 3
+ OPENSENT BGPState = 4
+ OPENCONFIRM BGPState = 5
+ ESTABLISHED BGPState = 6
+)
+
+func packValues(values []interface{}) ([]byte, error) {
+ b := new(bytes.Buffer)
+ for _, v := range values {
+ err := binary.Write(b, binary.BigEndian, v)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return b.Bytes(), nil
+}
+
+type MRTHeader struct {
+ Timestamp uint32
+ Type MRTType
+ SubType uint16
+ Len uint32
+}
+
+func (h *MRTHeader) DecodeFromBytes(data []byte) error {
+ if len(data) < MRT_COMMON_HEADER_LEN {
+ return fmt.Errorf("not all MRTHeader bytes are available. expected: %d, actual: %d", MRT_COMMON_HEADER_LEN, len(data))
+ }
+ h.Timestamp = binary.BigEndian.Uint32(data[:4])
+ h.Type = MRTType(binary.BigEndian.Uint16(data[4:6]))
+ h.SubType = binary.BigEndian.Uint16(data[6:8])
+ h.Len = binary.BigEndian.Uint32(data[8:12])
+ return nil
+}
+
+func (h *MRTHeader) Serialize() ([]byte, error) {
+ return packValues([]interface{}{h.Timestamp, h.Type, h.SubType, h.Len})
+}
+
+func NewMRTHeader(timestamp uint32, t MRTType, subtype MRTSubTyper, l uint32) (*MRTHeader, error) {
+ return &MRTHeader{
+ Timestamp: timestamp,
+ Type: t,
+ SubType: subtype.ToUint16(),
+ Len: l,
+ }, nil
+}
+
+type MRTMessage struct {
+ Header MRTHeader
+ Body Body
+}
+
+type Body interface {
+ DecodeFromBytes([]byte) error
+ Serialize() ([]byte, error)
+}
+
+type Peer struct {
+ Type uint8
+ BgpId net.IP
+ IpAddress net.IP
+ AS uint32
+}
+
+func (p *Peer) DecodeFromBytes(data []byte) ([]byte, error) {
+ notAllBytesAvail := fmt.Errorf("not all Peer bytes are available")
+ if len(data) < 5 {
+ return nil, notAllBytesAvail
+ }
+ p.Type = uint8(data[0])
+ p.BgpId = net.IP(data[1:5])
+ data = data[5:]
+
+ if p.Type&1 > 0 {
+ if len(data) < 16 {
+ return nil, notAllBytesAvail
+ }
+ p.IpAddress = net.IP(data[:16])
+ data = data[16:]
+ } else {
+ if len(data) < 4 {
+ return nil, notAllBytesAvail
+ }
+ p.IpAddress = net.IP(data[:4])
+ data = data[4:]
+ }
+
+ if p.Type&(1<<1) > 0 {
+ if len(data) < 4 {
+ return nil, notAllBytesAvail
+ }
+ p.AS = binary.BigEndian.Uint32(data[:4])
+ data = data[4:]
+ } else {
+ if len(data) < 2 {
+ return nil, notAllBytesAvail
+ }
+ p.AS = uint32(binary.BigEndian.Uint16(data[:2]))
+ data = data[2:]
+ }
+
+ return data, nil
+}
+
+func (p *Peer) Serialize() ([]byte, error) {
+ var err error
+ var bbuf []byte
+ buf := make([]byte, 5)
+ buf[0] = uint8(p.Type)
+ if p.BgpId.To4() == nil {
+ return nil, fmt.Errorf("invalid BGP ID")
+ }
+ copy(buf[1:], p.BgpId.To4())
+ if p.Type&1 > 0 {
+ buf = append(buf, p.IpAddress.To16()...)
+ } else {
+ buf = append(buf, p.IpAddress.To4()...)
+ }
+ if p.Type&(1<<1) > 0 {
+ bbuf, err = packValues([]interface{}{p.AS})
+ } else {
+ if p.AS > uint32(math.MaxUint16) {
+ return nil, fmt.Errorf("AS number is beyond 2 octet. %d > %d", p.AS, math.MaxUint16)
+ }
+ bbuf, err = packValues([]interface{}{uint16(p.AS)})
+ }
+ if err != nil {
+ return nil, err
+ }
+ return append(buf, bbuf...), nil
+}
+
+func NewPeer(bgpid string, ipaddr string, asn uint32, isAS4 bool) *Peer {
+ t := 0
+ addr := net.ParseIP(ipaddr).To4()
+ if addr == nil {
+ t |= 1
+ addr = net.ParseIP(ipaddr).To16()
+ }
+ if isAS4 {
+ t |= (1 << 1)
+ }
+ return &Peer{
+ Type: uint8(t),
+ BgpId: net.ParseIP(bgpid).To4(),
+ IpAddress: addr,
+ AS: asn,
+ }
+}
+
+func (p *Peer) String() string {
+ return fmt.Sprintf("PEER ENTRY: ID [%s] Addr [%s] AS [%d]", p.BgpId, p.IpAddress, p.AS)
+}
+
+type PeerIndexTable struct {
+ CollectorBgpId net.IP
+ ViewName string
+ Peers []*Peer
+}
+
+func (t *PeerIndexTable) DecodeFromBytes(data []byte) error {
+ notAllBytesAvail := fmt.Errorf("not all PeerIndexTable bytes are available")
+ if len(data) < 6 {
+ return notAllBytesAvail
+ }
+ t.CollectorBgpId = net.IP(data[:4])
+ viewLen := binary.BigEndian.Uint16(data[4:6])
+ if len(data) < 6+int(viewLen) {
+ return notAllBytesAvail
+ }
+ t.ViewName = string(data[6 : 6+viewLen])
+
+ data = data[6+viewLen:]
+
+ if len(data) < 2 {
+ return notAllBytesAvail
+ }
+ peerNum := binary.BigEndian.Uint16(data[:2])
+ data = data[2:]
+ t.Peers = make([]*Peer, 0, peerNum)
+ var err error
+ for i := 0; i < int(peerNum); i++ {
+ p := &Peer{}
+ data, err = p.DecodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+ t.Peers = append(t.Peers, p)
+ }
+
+ return nil
+}
+
+func (t *PeerIndexTable) Serialize() ([]byte, error) {
+ buf := make([]byte, 8+len(t.ViewName))
+ copy(buf, t.CollectorBgpId.To4())
+ binary.BigEndian.PutUint16(buf[4:], uint16(len(t.ViewName)))
+ copy(buf[6:], t.ViewName)
+ binary.BigEndian.PutUint16(buf[6+len(t.ViewName):], uint16(len(t.Peers)))
+ for _, peer := range t.Peers {
+ bbuf, err := peer.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ }
+ return buf, nil
+}
+
+func NewPeerIndexTable(bgpid string, viewname string, peers []*Peer) *PeerIndexTable {
+ return &PeerIndexTable{
+ CollectorBgpId: net.ParseIP(bgpid).To4(),
+ ViewName: viewname,
+ Peers: peers,
+ }
+}
+
+func (t *PeerIndexTable) String() string {
+ return fmt.Sprintf("PEER_INDEX_TABLE: CollectorBgpId [%s] ViewName [%s] Peers [%s]", t.CollectorBgpId, t.ViewName, t.Peers)
+}
+
+type RibEntry struct {
+ PeerIndex uint16
+ OriginatedTime uint32
+ PathAttributes []PathAttributeInterface
+}
+
+func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
+ notAllBytesAvail := fmt.Errorf("not all RibEntry bytes are available")
+ if len(data) < 8 {
+ return nil, notAllBytesAvail
+ }
+ e.PeerIndex = binary.BigEndian.Uint16(data[:2])
+ e.OriginatedTime = binary.BigEndian.Uint32(data[2:6])
+ totalLen := binary.BigEndian.Uint16(data[6:8])
+ data = data[8:]
+ for attrLen := totalLen; attrLen > 0; {
+ p, err := GetPathAttribute(data)
+ if err != nil {
+ return nil, err
+ }
+ err = p.DecodeFromBytes(data)
+ if err != nil {
+ return nil, err
+ }
+ attrLen -= uint16(p.Len())
+ if len(data) < p.Len() {
+ return nil, notAllBytesAvail
+ }
+ data = data[p.Len():]
+ e.PathAttributes = append(e.PathAttributes, p)
+ }
+ return data, nil
+}
+
+func (e *RibEntry) Serialize() ([]byte, error) {
+ buf := make([]byte, 8)
+ binary.BigEndian.PutUint16(buf, e.PeerIndex)
+ binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime)
+ totalLen := 0
+ binary.BigEndian.PutUint16(buf[6:], uint16(totalLen))
+ for _, pattr := range e.PathAttributes {
+ bbuf, err := pattr.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ totalLen += len(bbuf)
+ }
+ binary.BigEndian.PutUint16(buf[6:], uint16(totalLen))
+ return buf, nil
+}
+
+func NewRibEntry(index uint16, time uint32, pathattrs []PathAttributeInterface) *RibEntry {
+ return &RibEntry{
+ PeerIndex: index,
+ OriginatedTime: time,
+ PathAttributes: pathattrs,
+ }
+}
+
+type Rib struct {
+ SequenceNumber uint32
+ Prefix AddrPrefixInterface
+ Entries []*RibEntry
+ RouteFamily RouteFamily
+}
+
+func (u *Rib) DecodeFromBytes(data []byte) error {
+ if len(data) < 4 {
+ return fmt.Errorf("Not all RibIpv4Unicast message bytes available")
+ }
+ u.SequenceNumber = binary.BigEndian.Uint32(data[:4])
+ data = data[4:]
+ afi, safi := RouteFamilyToAfiSafi(u.RouteFamily)
+ if afi == 0 && safi == 0 {
+ afi = binary.BigEndian.Uint16(data[:2])
+ safi = data[2]
+ data = data[3:]
+ }
+ prefix, err := NewPrefixFromRouteFamily(afi, safi)
+ if err != nil {
+ return err
+ }
+ err = prefix.DecodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+ u.Prefix = prefix
+ data = data[prefix.Len():]
+ entryNum := binary.BigEndian.Uint16(data[:2])
+ data = data[2:]
+ u.Entries = make([]*RibEntry, 0, entryNum)
+ for i := 0; i < int(entryNum); i++ {
+ e := &RibEntry{}
+ data, err = e.DecodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+ u.Entries = append(u.Entries, e)
+ }
+ return nil
+}
+
+func (u *Rib) Serialize() ([]byte, error) {
+ buf := make([]byte, 4)
+ binary.BigEndian.PutUint32(buf, u.SequenceNumber)
+ rf := AfiSafiToRouteFamily(u.Prefix.AFI(), u.Prefix.SAFI())
+ switch rf {
+ case RF_IPv4_UC, RF_IPv4_MC, RF_IPv6_UC, RF_IPv6_MC:
+ default:
+ bbuf := make([]byte, 0, 2)
+ binary.BigEndian.PutUint16(bbuf, u.Prefix.AFI())
+ buf = append(buf, bbuf...)
+ buf = append(buf, u.Prefix.SAFI())
+ }
+ bbuf, err := u.Prefix.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ bbuf, err = packValues([]interface{}{uint16(len(u.Entries))})
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ for _, entry := range u.Entries {
+ bbuf, err = entry.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ buf = append(buf, bbuf...)
+ }
+ return buf, nil
+}
+
+func NewRib(seq uint32, prefix AddrPrefixInterface, entries []*RibEntry) *Rib {
+ rf := AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI())
+ return &Rib{
+ SequenceNumber: seq,
+ Prefix: prefix,
+ Entries: entries,
+ RouteFamily: rf,
+ }
+}
+
+func (u *Rib) String() string {
+ return fmt.Sprintf("RIB: Seq [%d] Prefix [%s] Entries [%s]", u.SequenceNumber, u.Prefix, u.Entries)
+}
+
+type BGP4MPHeader struct {
+ PeerAS uint32
+ LocalAS uint32
+ InterfaceIndex uint16
+ AddressFamily uint16
+ PeerIpAddress net.IP
+ LocalIpAddress net.IP
+ isAS4 bool
+}
+
+func (m *BGP4MPHeader) decodeFromBytes(data []byte) ([]byte, error) {
+ if m.isAS4 && len(data) < 8 {
+ return nil, fmt.Errorf("Not all BGP4MPMessageAS4 bytes available")
+ } else if !m.isAS4 && len(data) < 4 {
+ return nil, fmt.Errorf("Not all BGP4MPMessageAS bytes available")
+ }
+
+ if m.isAS4 {
+ m.PeerAS = binary.BigEndian.Uint32(data[:4])
+ m.LocalAS = binary.BigEndian.Uint32(data[4:8])
+ data = data[8:]
+ } else {
+ m.PeerAS = uint32(binary.BigEndian.Uint16(data[:2]))
+ m.LocalAS = uint32(binary.BigEndian.Uint16(data[2:4]))
+ data = data[4:]
+ }
+ m.InterfaceIndex = binary.BigEndian.Uint16(data[:2])
+ m.AddressFamily = binary.BigEndian.Uint16(data[2:4])
+ switch m.AddressFamily {
+ case AFI_IP:
+ m.PeerIpAddress = net.IP(data[4:8]).To4()
+ m.LocalIpAddress = net.IP(data[8:12]).To4()
+ data = data[12:]
+ case AFI_IP6:
+ m.PeerIpAddress = net.IP(data[4:20])
+ m.LocalIpAddress = net.IP(data[20:36])
+ data = data[36:]
+ default:
+ return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily)
+ }
+ return data, nil
+}
+
+func (m *BGP4MPHeader) serialize() ([]byte, error) {
+ var values []interface{}
+ if m.isAS4 {
+ values = []interface{}{m.PeerAS, m.LocalAS, m.InterfaceIndex, m.AddressFamily}
+ } else {
+ values = []interface{}{uint16(m.PeerAS), uint16(m.LocalAS), m.InterfaceIndex, m.AddressFamily}
+ }
+ buf, err := packValues(values)
+ if err != nil {
+ return nil, err
+ }
+ var bbuf []byte
+ switch m.AddressFamily {
+ case AFI_IP:
+ bbuf = make([]byte, 8)
+ copy(bbuf, m.PeerIpAddress.To4())
+ copy(bbuf[4:], m.LocalIpAddress.To4())
+ case AFI_IP6:
+ bbuf = make([]byte, 32)
+ copy(bbuf, m.PeerIpAddress)
+ copy(bbuf[16:], m.LocalIpAddress)
+ default:
+ return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily)
+ }
+ return append(buf, bbuf...), nil
+}
+
+func newBGP4MPHeader(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool) (*BGP4MPHeader, error) {
+ var af uint16
+ paddr := net.ParseIP(peerip).To4()
+ laddr := net.ParseIP(localip).To4()
+ if paddr != nil && laddr != nil {
+ af = AFI_IP
+ } else {
+ paddr = net.ParseIP(peerip).To16()
+ laddr = net.ParseIP(localip).To16()
+ if paddr != nil && laddr != nil {
+ af = AFI_IP6
+ } else {
+ return nil, fmt.Errorf("Peer IP Address and Local IP Address must have the same address family")
+ }
+ }
+ return &BGP4MPHeader{
+ PeerAS: peeras,
+ LocalAS: localas,
+ InterfaceIndex: intfindex,
+ AddressFamily: af,
+ PeerIpAddress: paddr,
+ LocalIpAddress: laddr,
+ isAS4: isAS4,
+ }, nil
+}
+
+type BGP4MPStateChange struct {
+ *BGP4MPHeader
+ OldState BGPState
+ NewState BGPState
+}
+
+func (m *BGP4MPStateChange) DecodeFromBytes(data []byte) error {
+ rest, err := m.decodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+ if len(rest) < 4 {
+ return fmt.Errorf("Not all BGP4MPStateChange bytes available")
+ }
+ m.OldState = BGPState(binary.BigEndian.Uint16(rest[:2]))
+ m.NewState = BGPState(binary.BigEndian.Uint16(rest[2:4]))
+ return nil
+}
+
+func (m *BGP4MPStateChange) Serialize() ([]byte, error) {
+ buf, err := m.serialize()
+ if err != nil {
+ return nil, err
+ }
+ bbuf, err := packValues([]interface{}{m.OldState, m.NewState})
+ if err != nil {
+ return nil, err
+ }
+ return append(buf, bbuf...), nil
+}
+
+func NewBGP4MPStateChange(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, oldstate, newstate BGPState) *BGP4MPStateChange {
+ header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
+ return &BGP4MPStateChange{
+ BGP4MPHeader: header,
+ OldState: oldstate,
+ NewState: newstate,
+ }
+}
+
+type BGP4MPMessage struct {
+ *BGP4MPHeader
+ BGPMessage *BGPMessage
+ isLocal bool
+}
+
+func (m *BGP4MPMessage) DecodeFromBytes(data []byte) error {
+ rest, err := m.decodeFromBytes(data)
+ if err != nil {
+ return err
+ }
+
+ if len(rest) < BGP_HEADER_LENGTH {
+ return fmt.Errorf("Not all BGP4MPMessageAS4 bytes available")
+ }
+
+ msg, err := ParseBGPMessage(rest)
+ if err != nil {
+ return err
+ }
+ m.BGPMessage = msg
+ return nil
+}
+
+func (m *BGP4MPMessage) Serialize() ([]byte, error) {
+ buf, err := m.serialize()
+ if err != nil {
+ return nil, err
+ }
+ bbuf, err := m.BGPMessage.Serialize()
+ if err != nil {
+ return nil, err
+ }
+ return append(buf, bbuf...), nil
+}
+
+func NewBGP4MPMessage(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *BGPMessage) *BGP4MPMessage {
+ header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
+ return &BGP4MPMessage{
+ BGP4MPHeader: header,
+ BGPMessage: msg,
+ }
+}
+
+func NewBGP4MPMessageLocal(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *BGPMessage) *BGP4MPMessage {
+ header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
+ return &BGP4MPMessage{
+ BGP4MPHeader: header,
+ BGPMessage: msg,
+ isLocal: true,
+ }
+}
+
+func (m *BGP4MPMessage) String() string {
+ title := "BGP4MP_MSG"
+ if m.isAS4 {
+ title += "_AS4"
+ }
+ if m.isLocal {
+ title += "_LOCAL"
+ }
+ return fmt.Sprintf("%s: PeerAS [%d] LocalAS [%d] InterfaceIndex [%d] PeerIP [%s] LocalIP [%s] BGPMessage [%s]", title, m.PeerAS, m.LocalAS, m.InterfaceIndex, m.PeerIpAddress, m.LocalIpAddress, m.BGPMessage)
+}
+
+func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
+ if len(data) < int(h.Len) {
+ return nil, fmt.Errorf("Not all MRT message bytes available. expected: %d, actual: %d", int(h.Len), len(data))
+ }
+ msg := &MRTMessage{Header: *h}
+ switch h.Type {
+ case TABLE_DUMPv2:
+ subType := MRTSubTypeTableDumpv2(h.SubType)
+ rf := RouteFamily(0)
+ switch subType {
+ case PEER_INDEX_TABLE:
+ msg.Body = &PeerIndexTable{}
+ case RIB_IPV4_UNICAST:
+ rf = RF_IPv4_UC
+ case RIB_IPV4_MULTICAST:
+ rf = RF_IPv4_MC
+ case RIB_IPV6_UNICAST:
+ rf = RF_IPv6_UC
+ case RIB_IPV6_MULTICAST:
+ rf = RF_IPv6_MC
+ case RIB_GENERIC:
+ default:
+ return nil, fmt.Errorf("unsupported table dumpv2 subtype: %s\n", subType)
+ }
+
+ if subType != PEER_INDEX_TABLE {
+ msg.Body = &Rib{
+ RouteFamily: rf,
+ }
+ }
+ case BGP4MP:
+ subType := MRTSubTypeBGP4MP(h.SubType)
+ isAS4 := true
+ switch subType {
+ case STATE_CHANGE:
+ isAS4 = false
+ fallthrough
+ case STATE_CHANGE_AS4:
+ msg.Body = &BGP4MPStateChange{
+ BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
+ }
+ case MESSAGE:
+ isAS4 = false
+ fallthrough
+ case MESSAGE_AS4:
+ msg.Body = &BGP4MPMessage{
+ BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
+ }
+ case MESSAGE_LOCAL:
+ isAS4 = false
+ fallthrough
+ case MESSAGE_AS4_LOCAL:
+ msg.Body = &BGP4MPMessage{
+ BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
+ isLocal: true,
+ }
+ default:
+ return nil, fmt.Errorf("unsupported bgp4mp subtype: %s\n", subType)
+ }
+ default:
+ return nil, fmt.Errorf("unsupported type: %s\n", h.Type)
+ }
+ err := msg.Body.DecodeFromBytes(data)
+ if err != nil {
+ return nil, err
+ }
+ return msg, nil
+}
diff --git a/packet/mrt_test.go b/packet/mrt_test.go
new file mode 100644
index 00000000..7aa073c4
--- /dev/null
+++ b/packet/mrt_test.go
@@ -0,0 +1,183 @@
+// Copyright (C) 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 (
+ "github.com/stretchr/testify/assert"
+ "reflect"
+ "testing"
+ "time"
+)
+
+func TestMrtHdr(t *testing.T) {
+ h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
+ if err != nil {
+ t.Fatal(err)
+ }
+ b1, err := h1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ h2 := &MRTHeader{}
+ err = h2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, reflect.DeepEqual(h1, h2), true)
+}
+
+func testPeer(t *testing.T, p1 *Peer) {
+ b1, err := p1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ p2 := &Peer{}
+ rest, err := p2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, len(rest), 0)
+ assert.Equal(t, reflect.DeepEqual(p1, p2), true)
+}
+
+func TestMrtPeer(t *testing.T) {
+ p := NewPeer("192.168.0.1", "10.0.0.1", 65000, false)
+ testPeer(t, p)
+}
+
+func TestMrtPeerv6(t *testing.T) {
+ p := NewPeer("192.168.0.1", "2001::1", 65000, false)
+ testPeer(t, p)
+}
+
+func TestMrtPeerAS4(t *testing.T) {
+ p := NewPeer("192.168.0.1", "2001::1", 135500, true)
+ testPeer(t, p)
+}
+
+func TestMrtPeerIndexTable(t *testing.T) {
+ p1 := NewPeer("192.168.0.1", "10.0.0.1", 65000, false)
+ p2 := NewPeer("192.168.0.1", "2001::1", 65000, false)
+ p3 := NewPeer("192.168.0.1", "2001::1", 135500, true)
+ pt1 := NewPeerIndexTable("192.168.0.1", "test", []*Peer{p1, p2, p3})
+ b1, err := pt1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ pt2 := &PeerIndexTable{}
+ err = pt2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, reflect.DeepEqual(pt1, pt2), true)
+}
+
+func TestMrtRibEntry(t *testing.T) {
+ aspath1 := []AsPathParamInterface{
+ NewAsPathParam(2, []uint16{1000}),
+ NewAsPathParam(1, []uint16{1001, 1002}),
+ NewAsPathParam(2, []uint16{1003, 1004}),
+ }
+
+ p := []PathAttributeInterface{
+ NewPathAttributeOrigin(3),
+ NewPathAttributeAsPath(aspath1),
+ NewPathAttributeNextHop("129.1.1.2"),
+ NewPathAttributeMultiExitDisc(1 << 20),
+ NewPathAttributeLocalPref(1 << 22),
+ }
+
+ e1 := NewRibEntry(1, uint32(time.Now().Unix()), p)
+ b1, err := e1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ e2 := &RibEntry{}
+ rest, err := e2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, len(rest), 0)
+ assert.Equal(t, reflect.DeepEqual(e1, e2), true)
+}
+
+func TestMrtRib(t *testing.T) {
+ aspath1 := []AsPathParamInterface{
+ NewAsPathParam(2, []uint16{1000}),
+ NewAsPathParam(1, []uint16{1001, 1002}),
+ NewAsPathParam(2, []uint16{1003, 1004}),
+ }
+
+ p := []PathAttributeInterface{
+ NewPathAttributeOrigin(3),
+ NewPathAttributeAsPath(aspath1),
+ NewPathAttributeNextHop("129.1.1.2"),
+ NewPathAttributeMultiExitDisc(1 << 20),
+ NewPathAttributeLocalPref(1 << 22),
+ }
+
+ e1 := NewRibEntry(1, uint32(time.Now().Unix()), p)
+ e2 := NewRibEntry(2, uint32(time.Now().Unix()), p)
+ e3 := NewRibEntry(3, uint32(time.Now().Unix()), p)
+
+ r1 := NewRib(1, NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3})
+ b1, err := r1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ r2 := &Rib{
+ RouteFamily: RF_IPv4_UC,
+ }
+ err = r2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, reflect.DeepEqual(r1, r2), true)
+}
+
+func TestMrtBgp4mpStateChange(t *testing.T) {
+ c1 := NewBGP4MPStateChange(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, ACTIVE, ESTABLISHED)
+ b1, err := c1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ c2 := &BGP4MPStateChange{BGP4MPHeader: &BGP4MPHeader{}}
+ err = c2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = c2.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, reflect.DeepEqual(c1, c2), true)
+}
+
+func TestMrtBgp4mpMessage(t *testing.T) {
+ msg := NewBGPKeepAliveMessage()
+ m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg)
+ b1, err := m1.Serialize()
+ if err != nil {
+ t.Fatal(err)
+ }
+ m2 := &BGP4MPMessage{BGP4MPHeader: &BGP4MPHeader{}}
+ err = m2.DecodeFromBytes(b1)
+ if err != nil {
+ t.Fatal(err)
+ }
+ assert.Equal(t, reflect.DeepEqual(m1, m2), true)
+}