diff options
Diffstat (limited to 'packet/mrt')
-rw-r--r-- | packet/mrt/mrt.go | 1006 | ||||
-rw-r--r-- | packet/mrt/mrt_test.go | 301 |
2 files changed, 0 insertions, 1307 deletions
diff --git a/packet/mrt/mrt.go b/packet/mrt/mrt.go deleted file mode 100644 index 9c6fef6d..00000000 --- a/packet/mrt/mrt.go +++ /dev/null @@ -1,1006 +0,0 @@ -// 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 mrt - -import ( - "bytes" - "encoding/binary" - "fmt" - "math" - "net" - "time" - - "github.com/osrg/gobgp/packet/bgp" -) - -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 - GEO_PEER_TABLE MRTSubTypeTableDumpv2 = 7 // RFC6397 - RIB_IPV4_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 8 // RFC8050 - RIB_IPV4_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 9 // RFC8050 - RIB_IPV6_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 10 // RFC8050 - RIB_IPV6_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 11 // RFC8050 - RIB_GENERIC_ADDPATH MRTSubTypeTableDumpv2 = 12 // RFC8050 -) - -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 - MESSAGE_ADDPATH MRTSubTypeBGP4MP = 8 // RFC8050 - MESSAGE_AS4_ADDPATH MRTSubTypeBGP4MP = 9 // RFC8050 - MESSAGE_LOCAL_ADDPATH MRTSubTypeBGP4MP = 10 // RFC8050 - MESSAGE_AS4_LOCAL_ADDPATH MRTSubTypeBGP4MP = 11 // RFC8050 -) - -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 -} - -func (h *MRTHeader) GetTime() time.Time { - t := int64(h.Timestamp) - return time.Unix(t, 0) -} - -type MRTMessage struct { - Header MRTHeader - Body Body -} - -func (m *MRTMessage) Serialize() ([]byte, error) { - buf, err := m.Body.Serialize() - if err != nil { - return nil, err - } - m.Header.Len = uint32(len(buf)) - bbuf, err := m.Header.Serialize() - if err != nil { - return nil, err - } - return append(bbuf, buf...), nil -} - -func NewMRTMessage(timestamp uint32, t MRTType, subtype MRTSubTyper, body Body) (*MRTMessage, error) { - header, err := NewMRTHeader(timestamp, t, subtype, 0) - if err != nil { - return nil, err - } - return &MRTMessage{ - Header: *header, - Body: body, - }, nil -} - -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) - 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 - PathIdentifier uint32 - PathAttributes []bgp.PathAttributeInterface - isAddPath bool -} - -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]) - if e.isAddPath { - e.PathIdentifier = binary.BigEndian.Uint32(data[6:10]) - data = data[10:] - } else { - data = data[6:] - } - totalLen := binary.BigEndian.Uint16(data[:2]) - data = data[2:] - for attrLen := totalLen; attrLen > 0; { - p, err := bgp.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) { - pbuf := make([]byte, 0) - totalLen := 0 - for _, pattr := range e.PathAttributes { - // TODO special modification is needed for MP_REACH_NLRI - // but also Quagga doesn't implement this. - // - // RFC 6396 4.3.4 - // There is one exception to the encoding of BGP attributes for the BGP - // MP_REACH_NLRI attribute (BGP Type Code 14). - // Since the AFI, SAFI, and NLRI information is already encoded - // in the RIB Entry Header or RIB_GENERIC Entry Header, - // only the Next Hop Address Length and Next Hop Address fields are included. - - pb, err := pattr.Serialize() - if err != nil { - return nil, err - } - pbuf = append(pbuf, pb...) - totalLen += len(pb) - } - var buf []byte - if e.isAddPath { - buf = make([]byte, 12) - binary.BigEndian.PutUint16(buf, e.PeerIndex) - binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime) - binary.BigEndian.PutUint32(buf[6:], e.PathIdentifier) - binary.BigEndian.PutUint16(buf[10:], uint16(totalLen)) - } else { - buf = make([]byte, 8) - binary.BigEndian.PutUint16(buf, e.PeerIndex) - binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime) - binary.BigEndian.PutUint16(buf[6:], uint16(totalLen)) - } - buf = append(buf, pbuf...) - return buf, nil -} - -func NewRibEntry(index uint16, time uint32, pathId uint32, pathAttrs []bgp.PathAttributeInterface, isAddPath bool) *RibEntry { - return &RibEntry{ - PeerIndex: index, - OriginatedTime: time, - PathIdentifier: pathId, - PathAttributes: pathAttrs, - isAddPath: isAddPath, - } -} - -func (e *RibEntry) String() string { - if e.isAddPath { - return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathIdentifier[%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathIdentifier, e.PathAttributes) - } else { - return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes) - } - -} - -type Rib struct { - SequenceNumber uint32 - Prefix bgp.AddrPrefixInterface - Entries []*RibEntry - RouteFamily bgp.RouteFamily - isAddPath bool -} - -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 := bgp.RouteFamilyToAfiSafi(u.RouteFamily) - if afi == 0 && safi == 0 { - afi = binary.BigEndian.Uint16(data[:2]) - safi = data[2] - data = data[3:] - } - prefix, err := bgp.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{ - isAddPath: u.isAddPath, - } - 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 := bgp.AfiSafiToRouteFamily(u.Prefix.AFI(), u.Prefix.SAFI()) - switch rf { - case bgp.RF_IPv4_UC, bgp.RF_IPv4_MC, bgp.RF_IPv6_UC, bgp.RF_IPv6_MC: - default: - bbuf := make([]byte, 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 bgp.AddrPrefixInterface, entries []*RibEntry) *Rib { - rf := bgp.AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI()) - return &Rib{ - SequenceNumber: seq, - Prefix: prefix, - Entries: entries, - RouteFamily: rf, - isAddPath: entries[0].isAddPath, - } -} - -func (u *Rib) String() string { - return fmt.Sprintf("RIB: Seq [%d] Prefix [%s] Entries [%s]", u.SequenceNumber, u.Prefix, u.Entries) -} - -type GeoPeer struct { - Type uint8 - BgpId net.IP - Latitude float32 - Longitude float32 -} - -func (p *GeoPeer) DecodeFromBytes(data []byte) ([]byte, error) { - if len(data) < 13 { - return nil, fmt.Errorf("not all GeoPeer bytes are available") - } - // Peer IP Address and Peer AS should not be included - p.Type = uint8(data[0]) - if p.Type != uint8(0) { - return nil, fmt.Errorf("unsupported peer type for GeoPeer: %d", p.Type) - } - p.BgpId = net.IP(data[1:5]) - p.Latitude = math.Float32frombits(binary.BigEndian.Uint32(data[5:9])) - p.Longitude = math.Float32frombits(binary.BigEndian.Uint32(data[9:13])) - return data[13:], nil -} - -func (p *GeoPeer) Serialize() ([]byte, error) { - buf := make([]byte, 13) - buf[0] = uint8(0) // Peer IP Address and Peer AS should not be included - bgpId := p.BgpId.To4() - if bgpId == nil { - return nil, fmt.Errorf("invalid BgpId: %s", p.BgpId) - } - copy(buf[1:5], bgpId) - binary.BigEndian.PutUint32(buf[5:9], math.Float32bits(p.Latitude)) - binary.BigEndian.PutUint32(buf[9:13], math.Float32bits(p.Longitude)) - return buf, nil -} - -func NewGeoPeer(bgpid string, latitude float32, longitude float32) *GeoPeer { - return &GeoPeer{ - Type: 0, // Peer IP Address and Peer AS should not be included - BgpId: net.ParseIP(bgpid).To4(), - Latitude: latitude, - Longitude: longitude, - } -} - -func (p *GeoPeer) String() string { - return fmt.Sprintf("PEER ENTRY: ID [%s] Latitude [%f] Longitude [%f]", p.BgpId, p.Latitude, p.Longitude) -} - -type GeoPeerTable struct { - CollectorBgpId net.IP - CollectorLatitude float32 - CollectorLongitude float32 - Peers []*GeoPeer -} - -func (t *GeoPeerTable) DecodeFromBytes(data []byte) error { - if len(data) < 14 { - return fmt.Errorf("not all GeoPeerTable bytes are available") - } - t.CollectorBgpId = net.IP(data[0:4]) - t.CollectorLatitude = math.Float32frombits(binary.BigEndian.Uint32(data[4:8])) - t.CollectorLongitude = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) - peerCount := binary.BigEndian.Uint16(data[12:14]) - data = data[14:] - t.Peers = make([]*GeoPeer, 0, peerCount) - var err error - for i := 0; i < int(peerCount); i++ { - p := &GeoPeer{} - if data, err = p.DecodeFromBytes(data); err != nil { - return err - } - t.Peers = append(t.Peers, p) - } - return nil -} - -func (t *GeoPeerTable) Serialize() ([]byte, error) { - buf := make([]byte, 14) - collectorBgpId := t.CollectorBgpId.To4() - if collectorBgpId == nil { - return nil, fmt.Errorf("invalid CollectorBgpId: %s", t.CollectorBgpId) - } - copy(buf[0:4], collectorBgpId) - binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(t.CollectorLatitude)) - binary.BigEndian.PutUint32(buf[8:12], math.Float32bits(t.CollectorLongitude)) - binary.BigEndian.PutUint16(buf[12:14], uint16(len(t.Peers))) - for _, peer := range t.Peers { - pbuf, err := peer.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - return buf, nil -} - -func NewGeoPeerTable(bgpid string, latitude float32, longitude float32, peers []*GeoPeer) *GeoPeerTable { - return &GeoPeerTable{ - CollectorBgpId: net.ParseIP(bgpid).To4(), - CollectorLatitude: latitude, - CollectorLongitude: longitude, - Peers: peers, - } -} - -func (t *GeoPeerTable) String() string { - return fmt.Sprintf("GEO_PEER_TABLE: CollectorBgpId [%s] CollectorLatitude [%f] CollectorLongitude [%f] Peers [%s]", t.CollectorBgpId, t.CollectorLatitude, t.CollectorLongitude, t.Peers) -} - -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 bgp.AFI_IP: - m.PeerIpAddress = net.IP(data[4:8]).To4() - m.LocalIpAddress = net.IP(data[8:12]).To4() - data = data[12:] - case bgp.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 bgp.AFI_IP: - bbuf = make([]byte, 8) - copy(bbuf, m.PeerIpAddress.To4()) - copy(bbuf[4:], m.LocalIpAddress.To4()) - case bgp.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 = bgp.AFI_IP - } else { - paddr = net.ParseIP(peerip).To16() - laddr = net.ParseIP(localip).To16() - if paddr != nil && laddr != nil { - af = bgp.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 *bgp.BGPMessage - BGPMessagePayload []byte - isLocal bool - isAddPath bool -} - -func (m *BGP4MPMessage) DecodeFromBytes(data []byte) error { - rest, err := m.decodeFromBytes(data) - if err != nil { - return err - } - - if len(rest) < bgp.BGP_HEADER_LENGTH { - return fmt.Errorf("Not all BGP4MPMessageAS4 bytes available") - } - - msg, err := bgp.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 - } - if m.BGPMessagePayload != nil { - return append(buf, m.BGPMessagePayload...), nil - } - 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 *bgp.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 *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isLocal: true, - } -} - -func NewBGP4MPMessageAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isAddPath: true, - } -} - -func NewBGP4MPMessageLocalAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isLocal: true, - isAddPath: true, - } -} - -func (m *BGP4MPMessage) String() string { - title := "BGP4MP_MSG" - if m.isAS4 { - title += "_AS4" - } - if m.isLocal { - title += "_LOCAL" - } - if m.isAddPath { - title += "_ADDPATH" - } - return fmt.Sprintf("%s: PeerAS [%d] LocalAS [%d] InterfaceIndex [%d] PeerIP [%s] LocalIP [%s] BGPMessage [%v]", title, m.PeerAS, m.LocalAS, m.InterfaceIndex, m.PeerIpAddress, m.LocalIpAddress, m.BGPMessage) -} - -//This function can be passed into a bufio.Scanner.Split() to read buffered mrt msgs -func SplitMrt(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 { - return 0, nil, nil - } - if cap(data) < MRT_COMMON_HEADER_LEN { // read more - return 0, nil, nil - } - //this reads the data - hdr := &MRTHeader{} - errh := hdr.DecodeFromBytes(data[:MRT_COMMON_HEADER_LEN]) - if errh != nil { - return 0, nil, errh - } - totlen := int(hdr.Len + MRT_COMMON_HEADER_LEN) - if len(data) < totlen { //need to read more - return 0, nil, nil - } - return totlen, data[0:totlen], nil -} - -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 := bgp.RouteFamily(0) - isAddPath := false - switch subType { - case PEER_INDEX_TABLE: - msg.Body = &PeerIndexTable{} - case RIB_IPV4_UNICAST: - rf = bgp.RF_IPv4_UC - case RIB_IPV4_MULTICAST: - rf = bgp.RF_IPv4_MC - case RIB_IPV6_UNICAST: - rf = bgp.RF_IPv6_UC - case RIB_IPV6_MULTICAST: - rf = bgp.RF_IPv6_MC - case RIB_GENERIC: - case GEO_PEER_TABLE: - msg.Body = &GeoPeerTable{} - case RIB_IPV4_UNICAST_ADDPATH: - rf = bgp.RF_IPv4_UC - isAddPath = true - case RIB_IPV4_MULTICAST_ADDPATH: - rf = bgp.RF_IPv4_MC - isAddPath = true - case RIB_IPV6_UNICAST_ADDPATH: - rf = bgp.RF_IPv6_UC - isAddPath = true - case RIB_IPV6_MULTICAST_ADDPATH: - rf = bgp.RF_IPv6_MC - isAddPath = true - case RIB_GENERIC_ADDPATH: - isAddPath = true - default: - return nil, fmt.Errorf("unsupported table dumpv2 subtype: %v\n", subType) - } - - if msg.Body == nil { - msg.Body = &Rib{ - RouteFamily: rf, - isAddPath: isAddPath, - } - } - 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, - } - case MESSAGE_ADDPATH: - isAS4 = false - fallthrough - case MESSAGE_AS4_ADDPATH: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - isAddPath: true, - } - case MESSAGE_LOCAL_ADDPATH: - isAS4 = false - fallthrough - case MESSAGE_AS4_LOCAL_ADDPATH: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - isLocal: true, - isAddPath: true, - } - default: - return nil, fmt.Errorf("unsupported bgp4mp subtype: %v\n", subType) - } - default: - return nil, fmt.Errorf("unsupported type: %v\n", h.Type) - } - err := msg.Body.DecodeFromBytes(data) - if err != nil { - return nil, err - } - return msg, nil -} diff --git a/packet/mrt/mrt_test.go b/packet/mrt/mrt_test.go deleted file mode 100644 index 30edd496..00000000 --- a/packet/mrt/mrt_test.go +++ /dev/null @@ -1,301 +0,0 @@ -// 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 mrt - -import ( - "bufio" - "bytes" - "github.com/osrg/gobgp/packet/bgp" - "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 TestMrtHdrTime(t *testing.T) { - h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20) - if err != nil { - t.Fatal(err) - } - ttime := time.Unix(10, 0) - htime := h1.GetTime() - t.Logf("this timestamp should be 10s after epoch:%v", htime) - assert.Equal(t, h1.GetTime(), ttime) -} - -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 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false) - 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 TestMrtRibEntryWithAddPath(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 200, p, true) - b1, err := e1.Serialize() - if err != nil { - t.Fatal(err) - } - - e2 := &RibEntry{isAddPath: true} - 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 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false) - e2 := NewRibEntry(2, uint32(time.Now().Unix()), 0, p, false) - e3 := NewRibEntry(3, uint32(time.Now().Unix()), 0, p, false) - - r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3}) - b1, err := r1.Serialize() - if err != nil { - t.Fatal(err) - } - r2 := &Rib{ - RouteFamily: bgp.RF_IPv4_UC, - } - err = r2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(r1, r2), true) -} - -func TestMrtRibWithAddPath(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 100, p, true) - e2 := NewRibEntry(2, uint32(time.Now().Unix()), 200, p, true) - e3 := NewRibEntry(3, uint32(time.Now().Unix()), 300, p, true) - - r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3}) - b1, err := r1.Serialize() - if err != nil { - t.Fatal(err) - } - r2 := &Rib{ - RouteFamily: bgp.RF_IPv4_UC, - isAddPath: true, - } - err = r2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(r1, r2), true) -} - -func TestMrtGeoPeerTable(t *testing.T) { - p1 := NewGeoPeer("192.168.0.1", 28.031157, 86.899684) - p2 := NewGeoPeer("192.168.0.1", 35.360556, 138.727778) - pt1 := NewGeoPeerTable("192.168.0.1", 12.345678, 98.765432, []*GeoPeer{p1, p2}) - b1, err := pt1.Serialize() - if err != nil { - t.Fatal(err) - } - pt2 := &GeoPeerTable{} - err = pt2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(pt1, pt2), 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 := bgp.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) -} - -func TestMrtSplit(t *testing.T) { - var b bytes.Buffer - numwrite, numread := 10, 0 - for i := 0; i < numwrite; i++ { - msg := bgp.NewBGPKeepAliveMessage() - m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg) - mm, _ := NewMRTMessage(1234, BGP4MP, MESSAGE, m1) - b1, err := mm.Serialize() - if err != nil { - t.Fatal(err) - } - b.Write(b1) - } - t.Logf("wrote %d serialized MRT keepalives in the buffer", numwrite) - r := bytes.NewReader(b.Bytes()) - scanner := bufio.NewScanner(r) - scanner.Split(SplitMrt) - for scanner.Scan() { - numread += 1 - } - t.Logf("scanner scanned %d serialized keepalives from the buffer", numread) - assert.Equal(t, numwrite, numread) -} |