summaryrefslogtreecommitdiffhomepage
path: root/packet
diff options
context:
space:
mode:
authorIWASE Yusuke <iwase.yusuke0@gmail.com>2017-06-06 15:19:54 +0900
committerIWASE Yusuke <iwase.yusuke0@gmail.com>2017-06-08 09:28:16 +0900
commit6b710bae425a222a43fbd615a3f4464c3361175d (patch)
tree5066c7ca696dfea7d4b37e0c28e383a5f0393ac7 /packet
parent7a34c7c0ed2a7fe332150af7bb001a24c1403969 (diff)
packet/mrt: BGP with Geo-Location Extensions (RFC6397)
This patch enables to decode/encode MRT format with BGP routing information including the geographical location which described in RFC6397. Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Diffstat (limited to 'packet')
-rw-r--r--packet/mrt/mrt.go114
-rw-r--r--packet/mrt/mrt_test.go16
2 files changed, 129 insertions, 1 deletions
diff --git a/packet/mrt/mrt.go b/packet/mrt/mrt.go
index 38be0e95..559455d1 100644
--- a/packet/mrt/mrt.go
+++ b/packet/mrt/mrt.go
@@ -67,6 +67,7 @@ const (
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
@@ -542,6 +543,115 @@ 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
@@ -812,6 +922,8 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
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
@@ -830,7 +942,7 @@ func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
return nil, fmt.Errorf("unsupported table dumpv2 subtype: %v\n", subType)
}
- if subType != PEER_INDEX_TABLE {
+ if msg.Body == nil {
msg.Body = &Rib{
RouteFamily: rf,
isAddPath: isAddPath,
diff --git a/packet/mrt/mrt_test.go b/packet/mrt/mrt_test.go
index 1b5978b0..e2e601a5 100644
--- a/packet/mrt/mrt_test.go
+++ b/packet/mrt/mrt_test.go
@@ -227,6 +227,22 @@ func TestMrtRibWithAddPath(t *testing.T) {
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()