Skip to content

Commit

Permalink
mpreachnlri support ipv6 unicast
Browse files Browse the repository at this point in the history
Signed-off-by: Peng Xiao <xiaoquwl@gmail.com>
  • Loading branch information
xiaopeng163 committed Dec 25, 2015
1 parent 7ac61dd commit f167110
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 10 deletions.
53 changes: 43 additions & 10 deletions yabgp/message/attribute/mpreachnlri.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"""

import struct
import binascii

import netaddr

Expand All @@ -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):
Expand Down Expand Up @@ -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):
Expand Down
39 changes: 39 additions & 0 deletions yabgp/tests/unit/message/attribute/test_mpreachnlri.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

0 comments on commit f167110

Please sign in to comment.