Skip to content

Commit

Permalink
Merge pull request #23 from xiaopeng163/master
Browse files Browse the repository at this point in the history
add attributes and init nlri
  • Loading branch information
xiaopeng163 committed Jul 17, 2015
2 parents 98a396b + 4ddd54f commit 9d0a916
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 1 deletion.
3 changes: 2 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ commands = python -m testtools.run \
yabgp.tests.unit.message.attribute.test_community \
yabgp.tests.unit.message.attribute.test_originatorid \
yabgp.tests.unit.message.attribute.test_clusterlist \
yabgp.tests.unit.message.attribute.test_extcommunity
yabgp.tests.unit.message.attribute.test_extcommunity \
yabgp.tests.unit.message.attribute.nlri.test_ipv4_mpls_vpn

[testenv:docs]
deps=
Expand Down
5 changes: 5 additions & 0 deletions yabgp/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@
# Unkonw
BGP_EXT_COM_UNKNOW = 0x0000

# route distinguisher type
BGP_ROUTE_DISTINGUISHER_TYPE_0 = 0x0000
BGP_ROUTE_DISTINGUISHER_TYPE_1 = 0x0001
BGP_ROUTE_DISTINGUISHER_TYPE_2 = 0x0001

# NLRI type as define in BGP flow spec RFC
BGPNLRI_FSPEC_DST_PFIX = 1 # RFC 5575
BGPNLRI_FSPEC_SRC_PFIX = 2 # RFC 5575
Expand Down
80 changes: 80 additions & 0 deletions yabgp/message/attribute/mpreachnlri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# 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.

"""BGP Attribute MP_REACH_NLRI
"""

import struct

from yabgp.message.attribute import Attribute
from yabgp.message.attribute import AttributeFlag
from yabgp.message.attribute import AttributeID
from yabgp.common import afn
from yabgp.common import safn
from yabgp.common import exception as excep
from yabgp.common import constants as bgp_cons
from yabgp.message.attribute.nlri.ipv4_mpls_vpn import IPv4MPLSVPN


class MpReachNLRI(Attribute):
"""
MP_REACH_NLRI (type code 14) is used to carry the set of reachable
destinations together with the next hop information to be used for
forwarding to these destinations (RFC 4760 page 2).
MP_REACH_NLRI coding information
+---------------------------------------------------------+
| Address Family Identifier (2 octets) |
+---------------------------------------------------------+
| Subsequent Address Family Identifier (1 octet) |
+---------------------------------------------------------+
| Length of Next Hop Network Address (1 octet) |
+---------------------------------------------------------+
| Network Address of Next Hop (variable) |
+---------------------------------------------------------+
| Reserved (1 octet) |
+---------------------------------------------------------+
| Network Layer Reachability Information (variable) |
+---------------------------------------------------------+
"""

ID = AttributeID.MP_REACH_NLRI
FLAG = AttributeFlag.OPTIONAL

@classmethod
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:]
except Exception:
# error when lenght is wrong
raise excep.UpdateMessageError(
sub_error=bgp_cons.ERR_MSG_UPDATE_ATTR_LEN,
data=repr(value))
if afi == afn.AFNUM_INET:
if safi == safn.SAFNUM_LAB_VPNUNICAST:
nlri = IPv4MPLSVPN.parse(nlri_data)

return {
'afi_safi': (afi, safi),
'nexthop': nexthop_data,
'nlri': nlri
}

@classmethod
def construct(cls, value):
pass
51 changes: 51 additions & 0 deletions yabgp/message/attribute/mpunreachnlri.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# 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.

"""BGP Attribute MP_UNREACH_NLRI
"""

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


class MpUnReachNLRI(Attribute):

"""
This is an optional non-transitive attribute that can be used for the
purpose of withdrawing multiple unfeasible routes from service.
An UPDATE message that contains the MP_UNREACH_NLRI is not required
to carry any other path attributes.
MP_UNREACH_NLRI coding information
+---------------------------------------------------------+
| Address Family Identifier (2 octets) |
+---------------------------------------------------------+
| Subsequent Address Family Identifier (1 octet) |
+---------------------------------------------------------+
| Withdrawn Routes (variable) |
+---------------------------------------------------------+
"""

ID = AttributeID.MP_UNREACH_NLRI
FLAG = AttributeFlag.OPTIONAL

@classmethod
def parse(cls, value):
pass

@classmethod
def construct(cls, value):
pass
Empty file.
33 changes: 33 additions & 0 deletions yabgp/message/attribute/nlri/ipv4_flow_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 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.

"""IPv4 Flowspec NLRI
"""


class IPv4FlowSpec(object):

@classmethod
def parse(cls, value):
"""
parse IPv4 flowspec NLRI
:param value:
:return:
"""
pass

@classmethod
def construct(cls, value):
pass
107 changes: 107 additions & 0 deletions yabgp/message/attribute/nlri/ipv4_mpls_vpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# coding=utf-8
# 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.

"""IPv4 MPLS VPN NLRI
"""

import struct
import logging
import binascii

import netaddr

from yabgp.common import constants as bgp_cons

LOG = logging.getLogger(__name__)


class IPv4MPLSVPN(object):

"""
IPv4 MPLS VPN NLRI
+---------------------------+
| Length (1 octet) |
+---------------------------+
| Label (3 octet) |
+---------------------------+
|...........................|
+---------------------------+
| Prefix (variable) |
+---------------------------+
a) Length: The Length field indicates the length, in bits, of the address prefix.
b) Label: (24 bits) Carries one or more labels in a stack, although a BGP update
has only one label. This field carries the following parts of the MPLS shim header:
Label Value–—20 Bits
Experimental bits—3 Bits
Bottom of stack bit—1 bit
c) Prefix: different coding way according to different SAFI
Route Distinguisher (8 bytes) plus IPv4 prefix (32 bits) or IPv6 prefix(128 bits)
rd (Route Distinguisher) structure (RFC 4364)
"""

@classmethod
def parse(cls, value):
"""
parse nlri
:param value: the raw hex nlri value
:return: nlri list
"""
nlri_list = []
while value:
nlri_dict = {}
# for python2 and python3
if isinstance(value[0], int):
prefix_bit_len = value[0]
else:
prefix_bit_len = ord(value[0])
if prefix_bit_len % 8 == 0:
prefix_byte_len = int(prefix_bit_len / 8)
else:
prefix_byte_len = int(prefix_bit_len / 8) + 1

label_int = int(binascii.b2a_hex(value[1:4]), 16)
nlri_dict['label'] = (label_int >> 4, label_int & 1)

rd = value[4:12]
rd_type = struct.unpack('!H', rd[0:2])[0]
rd_value = rd[2:8]
nlri_dict['rd_type'] = rd_type
if rd_type == bgp_cons.BGP_ROUTE_DISTINGUISHER_TYPE_0:
asn, an = struct.unpack('!HI', rd_value)
nlri_dict['rd'] = '%s:%s' % (asn, an)
elif rd_type == bgp_cons.BGP_ROUTE_DISTINGUISHER_TYPE_1:
ip = str(netaddr.IPAddress(struct.unpack('!I', rd_value[0:4])[0]))
an = struct.unpack('!H', rd_value[4:6])[0]
nlri_dict['rd'] = '%s:%s' % (ip, an)
elif rd_type == bgp_cons.BGP_ROUTE_DISTINGUISHER_TYPE_2:
asn, an = struct.unpack('!IH', rd_value)
nlri_dict['rd'] = '%s:%s' % (asn, an)
else:
LOG.warning('unknow rd type for nlri, type=%s' % rd_type)
nlri_dict['rd'] = '%s:%s' % (0, 0)
prefix = value[12:prefix_byte_len + 1]
if len(prefix) < 4:
prefix += '\x00' * (4 - len(prefix))
nlri_dict['str'] = str(netaddr.IPAddress(struct.unpack('!I', prefix)[0])) +\
'/%s' % (prefix_bit_len - 88)
value = value[prefix_byte_len + 1:]
nlri_list.append(nlri_dict)
return nlri_list

@classmethod
def contruct(cls, value):
pass
17 changes: 17 additions & 0 deletions yabgp/message/attribute/nlri/ipv6_mpls_vpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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.

"""IPv6 MPLS VPN NLRI
"""
Empty file.
31 changes: 31 additions & 0 deletions yabgp/tests/unit/message/attribute/nlri/test_ipv4_mpls_vpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 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.

""" Test IPv4 MPLS VPN NLRI """

import unittest

from yabgp.message.attribute.nlri.ipv4_mpls_vpn import IPv4MPLSVPN


class TestIPv4MPLSVPN(unittest.TestCase):

def test_parse(self):
nlri_hex = b'\x78\x00\x01\x91\x00\x00\x00\x64\x00\x00\x00\x64\xaa\x00\x00\x00'
self.assertEqual(
[{'label': (25, 1), 'rd': '100:100', 'rd_type': 0, 'str': '170.0.0.0/32'}], IPv4MPLSVPN.parse(nlri_hex))

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

0 comments on commit 9d0a916

Please sign in to comment.