From f16711026fad07544fc6efa5c5627784da65fc89 Mon Sep 17 00:00:00 2001 From: Peng Xiao Date: Fri, 25 Dec 2015 22:17:37 +0800 Subject: [PATCH] mpreachnlri support ipv6 unicast Signed-off-by: Peng Xiao --- yabgp/message/attribute/mpreachnlri.py | 53 +++++++++++++++---- .../message/attribute/test_mpreachnlri.py | 39 ++++++++++++++ 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/yabgp/message/attribute/mpreachnlri.py b/yabgp/message/attribute/mpreachnlri.py index df5f333..cddd08b 100644 --- a/yabgp/message/attribute/mpreachnlri.py +++ b/yabgp/message/attribute/mpreachnlri.py @@ -17,6 +17,7 @@ """ import struct +import binascii import netaddr @@ -29,6 +30,7 @@ from yabgp.common import constants as bgp_cons from yabgp.message.attribute.nlri.ipv4_mpls_vpn import IPv4MPLSVPN from yabgp.message.attribute.nlri.ipv4_flowspec import IPv4FlowSpec +from yabgp.message.attribute.nlri.ipv6_unicast import IPv6Unicast class MpReachNLRI(Attribute): @@ -61,31 +63,62 @@ def parse(cls, value): try: afi, safi, nexthop_length = struct.unpack('!HBB', value[0:4]) - nexthop_data = value[4:4 + nexthop_length] - nlri_data = value[5 + nexthop_length:] + nexthop_bin = value[4:4 + nexthop_length] + nlri_bin = value[5 + nexthop_length:] except Exception: # error when lenght is wrong raise excep.UpdateMessageError( sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN, data=repr(value)) + + # Address Family IPv4 if afi == afn.AFNUM_INET: if safi == safn.SAFNUM_LAB_VPNUNICAST: - nlri = IPv4MPLSVPN.parse(nlri_data) + nlri = IPv4MPLSVPN.parse(nlri_bin) elif safi == safn.SAFNUM_FSPEC_RULE: # if nlri length is greater than 240 bytes, it is encoded over 2 bytes - if len(nlri_data) >= 240: - nlri_data = nlri_data[2:] + if len(nlri_bin) >= 240: + nlri_bin = nlri_bin[2:] else: - nlri_data = nlri_data[1:] - nlri = IPv4FlowSpec.parse(nlri_data) + nlri_bin = nlri_bin[1:] + nlri = IPv4FlowSpec.parse(nlri_bin) else: - nlri = repr(nlri_data) + nlri = repr(nlri_bin) + + # # Address Family IPv6 + elif afi == afn.AFNUM_INET6: + # IPv6 unicast + if safi == safn.SAFNUM_UNICAST: + # decode nexthop + # RFC 2545 + # The value of the Length of Next Hop Network Address field on a + # MP_REACH_NLRI attribute shall be set to 16, when only a global + # address is present, or 32 if a link-local address is also included in + # the Next Hop field. + # + # The link-local address shall be included in the Next Hop field if and + # only if the BGP speaker shares a common subnet with the entity + # identified by the global IPv6 address carried in the Network Address + # of Next Hop field and the peer the route is being advertised to. + nexthop_addrlen = 16 + has_link_local = False + nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[:nexthop_addrlen]), 16))) + if len(nexthop_bin) == 2 * nexthop_addrlen: + # has link local address + has_link_local = True + linklocal_nexthop = str(netaddr.IPAddress(int(binascii.b2a_hex(nexthop_bin[nexthop_addrlen:]), 16))) + nlri = IPv6Unicast.parse(nlri_bin) + if has_link_local: + return dict(afi_safi=(afi, safi), nexthop=nexthop, linklocal_nexthop=linklocal_nexthop, nlri=nlri) + else: + return dict(afi_safi=(afi, safi), nexthop=nexthop, nlri=nlri) + else: - nlri = repr(nlri_data) + nlri = repr(nlri_bin) - return dict(afi_safi=(afi, safi), nexthop=nexthop_data, nlri=nlri) + return dict(afi_safi=(afi, safi), nexthop=nexthop_bin, nlri=nlri) @classmethod def construct(cls, value): diff --git a/yabgp/tests/unit/message/attribute/test_mpreachnlri.py b/yabgp/tests/unit/message/attribute/test_mpreachnlri.py index 082eced..0881acb 100644 --- a/yabgp/tests/unit/message/attribute/test_mpreachnlri.py +++ b/yabgp/tests/unit/message/attribute/test_mpreachnlri.py @@ -12,3 +12,42 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. + +""" Unittest for MPReach NLRI""" + +import unittest + +from yabgp.message.attribute.mpreachnlri import MpReachNLRI + + +class TestMpReachNLRI(unittest.TestCase): + + def setUp(self): + + self.maxDiff = None + + def test_ipv6_unicast(self): + + data_bin = b"\x00\x02\x01\x10\x20\x01\x32\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ + b"\x01\x00\x80\x20\x01\x32\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" \ + b"\x40\x20\x01\x32\x32\x00\x01\x00\x00\x7f\x20\x01\x48\x37\x16\x32\x00\x00\x00" \ + b"\x00\x00\x00\x00\x00\x00\x02" + data_hoped = { + 'afi_safi': (2, 1), + 'nexthop': '2001:3232::1', + 'nlri': ['2001:3232::1/128', '::2001:3232:1:0/64', '2001:4837:1632::2/127']} + self.assertEqual(data_hoped, MpReachNLRI.parse(data_bin)) + + def test_ipv6_unicast_with_linklocal_nexthop(self): + data_bin = b"\x00\x02\x01\x20\x20\x01\x0d\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \ + b"\x02\xfe\x80\x00\x00\x00\x00\x00\x00\xc0\x02\x0b\xff\xfe\x7e\x00\x00\x00\x40" \ + b"\x20\x01\x0d\xb8\x00\x02\x00\x02\x40\x20\x01\x0d\xb8\x00\x02\x00\x01\x40\x20" \ + b"\x01\x0d\xb8\x00\x02\x00\x00" + data_hoped = { + 'afi_safi': (2, 1), + 'linklocal_nexthop': 'fe80::c002:bff:fe7e:0', + 'nexthop': '2001:db8::2', + 'nlri': ['::2001:db8:2:2/64', '::2001:db8:2:1/64', '::2001:db8:2:0/64']} + self.assertEqual(data_hoped, MpReachNLRI.parse(data_bin)) +if __name__ == '__main__': + unittest.main()