Skip to content

Commit

Permalink
some tlvs for bgpls
Browse files Browse the repository at this point in the history
Signed-off-by: Peng Xiao <xiaoquwl@gmail.com>
  • Loading branch information
xiaopeng163 committed Apr 27, 2017
1 parent 6e5d557 commit 840ff9d
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 5 deletions.
2 changes: 1 addition & 1 deletion yabgp/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
BGPTYPE_SAFI_SPECIFIC_ATTR = 19 # draft-kapoor-nalawade-idr-bgp-ssa-00.txt
BGPTYPE_PMSI_TUNNEL = 22 # RFC 6514
BGPTYPE_TUNNEL_ENCAPS_ATTR = 23 # RFC5512
BGPTYPE_LINK_STATE = 99
BGPTYPE_LINK_STATE = 29
BGPTYPE_ATTRIBUTE_SET = 128

# BGP Tunnel Encapsulation Attribute Tunnel Types
Expand Down
2 changes: 1 addition & 1 deletion yabgp/message/attribute/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ class AttributeID(int):
Tunnel_Encapsulation_Attribute = 0x17 # 23 [RFC5512]
Traffic_Engineering = 0x18 # 24 [RFC5543]
IPv6_Address_Specific_Extended_Community = 0x19 # 25 [RFC5701]
# AIGP = 0x1a # 26 [draft-ietf-idr-aigp](TEMPORARY - expires 2012-03-14)

LINKSTATE = 0x1d
ATTR_SET = 0x80 # 128 [RFC6368]

Unassigned = list(range(27, 127)) + list(range(129, 254))
Expand Down
67 changes: 67 additions & 0 deletions yabgp/message/attribute/linkstate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Copyright 2015 Cisco Systems, Inc.
# All rights reserved.
#
# 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.

import struct
import binascii

from yabgp.message.attribute import Attribute
from yabgp.message.attribute import AttributeID
from yabgp.message.attribute import AttributeFlag


class LinkState(Attribute):
"""BGP Link State
"""

ID = AttributeID.LINKSTATE
FLAG = AttributeFlag.OPTIONAL
MULTIPLE = False

MUTI_TOPO_ID = 263
NODE_FLAG = 1024
OPA_NODE = 1025
NODE_NAME = 1026
ISIS_AREA_ID = 1027
IPV4_ROUTER_ID = 1028
IPV6_ROUTER_ID = 1029

@classmethod
def parse(cls, value):

"""
parse linkstate
:param value: raw binary value
"""
value_dict = dict()
while value:
_type, _len = struct.unpack('!HH', value[0:2])
_value = value[2: 2+_len]

if _type == cls.NODE_NAME:
value_dict[_type] = _value.decode('ascii')

else:
value_dict[_type] = binascii.b2a_hex(_value)

value = value[3+_len:]

return value_dict

@classmethod
def construct(cls, value):
"""
:param value: interger value
"""
pass
13 changes: 11 additions & 2 deletions yabgp/message/attribute/mpreachnlri.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from yabgp.message.attribute.nlri.ipv4_flowspec import IPv4FlowSpec
from yabgp.message.attribute.nlri.ipv6_unicast import IPv6Unicast
from yabgp.message.attribute.nlri.evpn import EVPN
from yabgp.message.attribute.nlri.linkstate import BGPLS


class MpReachNLRI(Attribute):
Expand Down Expand Up @@ -62,7 +63,8 @@ class MpReachNLRI(Attribute):

@classmethod
def parse(cls, value):

"""parse
"""
try:
afi, safi, nexthop_length = struct.unpack('!HBB', value[0:4])
nexthop_bin = value[4:4 + nexthop_length]
Expand All @@ -85,7 +87,6 @@ def parse(cls, value):
asn, an = struct.unpack('!HI', rd_value_bin)
ipv4 = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[8:]), 16)))
nexthop = {'rd': '%s:%s' % (asn, an), 'str': ipv4}
# TODO(xiaoquwl) for other RD type decoding
else:
nexthop = repr(nexthop_bin[8:])
# parse nlri
Expand Down Expand Up @@ -169,6 +170,14 @@ def parse(cls, value):
else:
nlri = repr(nlri_bin)

# BGP LS
elif afi == afn.AFNUM_BGPLS:
if safi == safn.SAFNUM_BGPLS:
nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin), 16)))
nlri = BGPLS.parse(nlri_bin)
return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri)
else:
pass
else:
nlri = repr(nlri_bin)

Expand Down
138 changes: 138 additions & 0 deletions yabgp/message/attribute/nlri/linkstate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Copyright 2016 Cisco Systems, Inc.
# All rights reserved.
#
# 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.
"""linkstate
"""

import struct
import binascii

import netaddr

from yabgp.message.attribute.nlri import NLRI


class BGPLS(NLRI):
"""BGPLS
"""
NODE_NLRI = 1
LINK_NLRI = 2
IPv4_TOPO_PREFIX_NLRI = 3
IPv6_TOPO_PREFIX_NLRI = 4

@classmethod
def parse(cls, nlri_data):
nlri_list = []
while nlri_data:
_type, length = struct.unpack('!HH', nlri_data[0:4])
value = nlri_data[4: 4 + length]
nlri_data = nlri_data[4+length:]
nlri = dict()
if _type == cls.LINK_NLRI:
nlri['type'] = 'link'
nlri['value'] = cls.parse_nlri(value)
nlri_list.append(nlri)
return nlri_list

@classmethod
def parse_nlri(cls, data):
"""parse nlri: node, link, prefix
"""
# 0 1 2 3
# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
# +-+-+-+-+-+-+-+-+
# | Protocol-ID |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# | Identifier |
# | (64 bits) |
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# // Local Node Descriptors (variable) //
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# // Remote Node Descriptors (variable) //
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# // Link Descriptors (variable) //
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# Figure 8: The Link NLRI format
return_data = []
# proto_id = struct.unpack('!B', data[0])[0]
descriptors = data[9:]
while descriptors:
_type, length = struct.unpack('!HH', descriptors[0:4])
value = descriptors[4: 4+length]
descriptors = descriptors[4+length:]
descriptor = dict()
if _type == 256: # local node
pass
elif _type == 257:
pass
elif _type == 258: # link local/remote identifier
pass
elif _type == 259: # ipv4 interface address
ipv4_addr = str(netaddr.IPAddress(int(binascii.b2a_hex(value), 16)))
descriptor['type'] = 'link_local_ipv4'
descriptor['value'] = ipv4_addr
return_data.append(descriptor)
elif _type == 260: # ipv4 neighbor address
ipv4_neighbor_addr = str(netaddr.IPAddress(int(binascii.b2a_hex(value), 16)))
descriptor['type'] = 'link_remote_ipv4'
descriptor['value'] = ipv4_neighbor_addr
return_data.append(descriptor)

return return_data

@classmethod
def parse_node_descriptor(cls, data):

# +--------------------+-------------------+----------+
# | Sub-TLV Code Point | Description | Length |
# +--------------------+-------------------+----------+
# | 512 | Autonomous System | 4 |
# | 513 | BGP-LS Identifier | 4 |
# | 514 | OSPF Area-ID | 4 |
# | 515 | IGP Router-ID | Variable |
# +--------------------+-------------------+----------+
return_data = dict()
while data:
_type, length = struct.unpack('!HH', data[0: 4])
value = data[4: 4+length]
data = data[4+length:]

if _type == 512:
pass
elif _type == 513:
return_data['bgpls_id'] = str(netaddr.IPAddress(int(binascii.b2a_hex(value), 16)))
elif _type == 514:
pass
return return_data

@classmethod
def parse_link_descriptor(cls, data):

# +-----------+---------------------+--------------+------------------+
# | TLV Code | Description | IS-IS TLV | Reference |
# | Point | | /Sub-TLV | (RFC/Section) |
# +-----------+---------------------+--------------+------------------+
# | 258 | Link Local/Remote | 22/4 | [RFC5307]/1.1 |
# | | Identifiers | | |
# | 259 | IPv4 interface | 22/6 | [RFC5305]/3.2 |
# | | address | | |
# | 260 | IPv4 neighbor | 22/8 | [RFC5305]/3.3 |
# | | address | | |
# | 261 | IPv6 interface | 22/12 | [RFC6119]/4.2 |
# | | address | | |
# | 262 | IPv6 neighbor | 22/13 | [RFC6119]/4.3 |
# | | address | | |
# | 263 | Multi-Topology | --- | Section 3.2.1.5 |
# | | Identifier | | |
pass
3 changes: 2 additions & 1 deletion yabgp/message/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import struct
import traceback
import logging
import binascii

import netaddr

Expand Down Expand Up @@ -368,7 +369,7 @@ def parse_attributes(data, asn4=False):
elif type_code == bgp_cons.BGPTYPE_PMSI_TUNNEL:
decode_value = PMSITunnel.parse(value=attr_value)
else:
decode_value = repr(attr_value)
decode_value = binascii.b2a_hex(attr_value)
attributes[type_code] = decode_value

return attributes
Expand Down
40 changes: 40 additions & 0 deletions yabgp/tests/unit/message/attribute/nlri/test_bgpls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2015-2017 Cisco Systems, Inc.
# All rights reserved.
#
# 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.

import unittest

from yabgp.message.attribute.nlri.linkstate import BGPLS


class TestBGPLS(unittest.TestCase):

def test_parse(self):

data_bin = b"\x00\x02\x00" \
b"\x55\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x02\x00" \
b"\x00\x04\x00\x00\xff\xfe\x02\x01\x00\x04\x00\x00\x00\x00\x02\x03" \
b"\x00\x06\x00\x00\x00\x00\x00\x03\x01\x01\x00\x1a\x02\x00\x00\x04" \
b"\x00\x00\xff\xfe\x02\x01\x00\x04\x00\x00\x00\x00\x02\x03\x00\x06" \
b"\x00\x00\x00\x00\x00\x01\x01\x03\x00\x04\x01\x03\x00\x02\x01\x04" \
b"\x00\x04\x01\x03\x00\x01"
data_dict = [
{
'value': [
{'value': '1.3.0.2', 'type': 'link_local_ipv4'},
{'value': '1.3.0.1', 'type': 'link_remote_ipv4'}],
'type': 'link'
}
]
self.assertEqual(data_dict, BGPLS.parse(data_bin))
23 changes: 23 additions & 0 deletions yabgp/tests/unit/message/attribute/test_mpreachnlri.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,29 @@ def test_l2vpn_evpn_parse_construct_route_type4(self):
}
self.assertEqual(data_dict, MpReachNLRI.parse(MpReachNLRI.construct(data_dict)[3:]))

def test_linkstate(self):
data = b"\x90\x0e\x00\x62\x40\x04\x47\x04\x0a\x7c\x01\x7e\x00\x00\x02\x00" \
b"\x55\x02\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x1a\x02\x00" \
b"\x00\x04\x00\x00\xff\xfe\x02\x01\x00\x04\x00\x00\x00\x00\x02\x03" \
b"\x00\x06\x00\x00\x00\x00\x00\x01\x01\x01\x00\x1a\x02\x00\x00\x04" \
b"\x00\x00\xff\xfe\x02\x01\x00\x04\x00\x00\x00\x00\x02\x03\x00\x06" \
b"\x00\x00\x00\x00\x00\x03\x01\x03\x00\x04\x01\x03\x00\x01\x01\x04" \
b"\x00\x04\x01\x03\x00\x02"
data_dict = {
'afi_safi': (16388, 71),
'nexthop': '10.124.1.126',
'nlri': [
{
'type': 'link',
'value': [
{'type': 'link_local_ipv4', 'value': '1.3.0.1'},
{'type': 'link_remote_ipv4', 'value': '1.3.0.2'}
]
}
]
}
self.assertEqual(data_dict, MpReachNLRI.parse(data[4:]))


if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit 840ff9d

Please sign in to comment.