diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2017-05-29 11:09:40 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2017-06-01 09:31:52 +0900 |
commit | 99336372ab2ae8a3b61af63abbcbd70223a1dfe1 (patch) | |
tree | 28d439e6d04884e78fb53279f8c3f43675743e49 /packet/mrt/mrt.go | |
parent | b529f81ed7d8428200a3f5dcf99a57db9f9f769e (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.go | 144 |
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) } |