summaryrefslogtreecommitdiffhomepage
path: root/packet/mrt/mrt.go
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-05-29 11:09:40 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2017-06-01 09:31:52 +0900
commit99336372ab2ae8a3b61af63abbcbd70223a1dfe1 (patch)
tree28d439e6d04884e78fb53279f8c3f43675743e49 /packet/mrt/mrt.go
parentb529f81ed7d8428200a3f5dcf99a57db9f9f769e (diff)
packet/mrt: BGP Additional Path Extensions (RFC8050)
This patch enables to decode/encode MRT format with BGP Additional Path Extensions which described in RFC8050. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Diffstat (limited to 'packet/mrt/mrt.go')
-rw-r--r--packet/mrt/mrt.go144
1 files changed, 119 insertions, 25 deletions
diff --git a/packet/mrt/mrt.go b/packet/mrt/mrt.go
index 8947648a..38be0e95 100644
--- a/packet/mrt/mrt.go
+++ b/packet/mrt/mrt.go
@@ -61,12 +61,17 @@ type MRTSubTyper interface {
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
+ 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
+ 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 {
@@ -76,12 +81,16 @@ func (t MRTSubTypeTableDumpv2) ToUint16() uint16 {
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
+ 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 {
@@ -344,7 +353,9 @@ func (t *PeerIndexTable) String() string {
type RibEntry struct {
PeerIndex uint16
OriginatedTime uint32
+ PathIdentifier uint32
PathAttributes []bgp.PathAttributeInterface
+ isAddPath bool
}
func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
@@ -354,8 +365,14 @@ func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
}
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:]
+ 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 {
@@ -376,11 +393,8 @@ func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
}
func (e *RibEntry) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint16(buf, e.PeerIndex)
- binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime)
+ pbuf := make([]byte, 0)
totalLen := 0
- binary.BigEndian.PutUint16(buf[6:], uint16(totalLen))
for _, pattr := range e.PathAttributes {
// TODO special modification is needed for MP_REACH_NLRI
// but also Quagga doesn't implement this.
@@ -392,27 +406,47 @@ func (e *RibEntry) Serialize() ([]byte, error) {
// in the RIB Entry Header or RIB_GENERIC Entry Header,
// only the Next Hop Address Length and Next Hop Address fields are included.
- bbuf, err := pattr.Serialize()
+ pb, err := pattr.Serialize()
if err != nil {
return nil, err
}
- buf = append(buf, bbuf...)
- totalLen += len(bbuf)
+ 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))
}
- binary.BigEndian.PutUint16(buf[6:], uint16(totalLen))
+ buf = append(buf, pbuf...)
return buf, nil
}
-func NewRibEntry(index uint16, time uint32, pathattrs []bgp.PathAttributeInterface) *RibEntry {
+func NewRibEntry(index uint16, time uint32, pathid uint32, pathattrs []bgp.PathAttributeInterface) *RibEntry {
return &RibEntry{
PeerIndex: index,
OriginatedTime: time,
+ PathIdentifier: pathid,
PathAttributes: pathattrs,
+ isAddPath: pathid != 0,
}
}
func (e *RibEntry) String() string {
- return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttrs [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes)
+ if e.isAddPath {
+ return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathIdentifier[%d] PathAttrs [%v]", e.PeerIndex, e.OriginatedTime, e.PathIdentifier, e.PathAttributes)
+ } else {
+ return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttrs [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes)
+ }
+
}
type Rib struct {
@@ -420,6 +454,7 @@ type Rib struct {
Prefix bgp.AddrPrefixInterface
Entries []*RibEntry
RouteFamily bgp.RouteFamily
+ isAddPath bool
}
func (u *Rib) DecodeFromBytes(data []byte) error {
@@ -448,7 +483,9 @@ func (u *Rib) DecodeFromBytes(data []byte) error {
data = data[2:]
u.Entries = make([]*RibEntry, 0, entryNum)
for i := 0; i < int(entryNum); i++ {
- e := &RibEntry{}
+ e := &RibEntry{
+ isAddPath: u.isAddPath,
+ }
data, err = e.DecodeFromBytes(data)
if err != nil {
return err
@@ -497,6 +534,7 @@ func NewRib(seq uint32, prefix bgp.AddrPrefixInterface, entries []*RibEntry) *Ri
Prefix: prefix,
Entries: entries,
RouteFamily: rf,
+ isAddPath: entries[0].isAddPath,
}
}
@@ -645,6 +683,7 @@ type BGP4MPMessage struct {
BGPMessage *bgp.BGPMessage
BGPMessagePayload []byte
isLocal bool
+ isAddPath bool
}
func (m *BGP4MPMessage) DecodeFromBytes(data []byte) error {
@@ -697,6 +736,25 @@ func NewBGP4MPMessageLocal(peeras, localas uint32, intfindex uint16, peerip, loc
}
}
+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 {
@@ -705,6 +763,9 @@ func (m *BGP4MPMessage) String() string {
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)
}
@@ -738,6 +799,7 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
case TABLE_DUMPv2:
subType := MRTSubTypeTableDumpv2(h.SubType)
rf := bgp.RouteFamily(0)
+ isAddPath := false
switch subType {
case PEER_INDEX_TABLE:
msg.Body = &PeerIndexTable{}
@@ -750,6 +812,20 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
case RIB_IPV6_MULTICAST:
rf = bgp.RF_IPv6_MC
case RIB_GENERIC:
+ 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)
}
@@ -757,6 +833,7 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
if subType != PEER_INDEX_TABLE {
msg.Body = &Rib{
RouteFamily: rf,
+ isAddPath: isAddPath,
}
}
case BGP4MP:
@@ -785,6 +862,23 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
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)
}