Skip to content

Commit

Permalink
parse and construct route type of mac ip advertisement
Browse files Browse the repository at this point in the history
Signed-off-by: Peng Xiao <xiaoquwl@gmail.com>
  • Loading branch information
xiaopeng163 committed Jan 22, 2016
1 parent c1e7d86 commit 3bbf54b
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 3 deletions.
160 changes: 157 additions & 3 deletions yabgp/message/attribute/nlri/evpn.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@
# License for the specific language governing permissions and limitations
# under the License.

import struct
import binascii

import netaddr

from yabgp.common import constants as bgp_cons
from yabgp.message.attribute.nlri import NLRI
from yabgp.message.attribute.nlri.mpls_vpn import MPLSVPN


class EVPN(MPLSVPN, NLRI):
class EVPN(NLRI):
"""
The format of the EVPN NLRI is as follows:
+-----------------------------------+
Expand All @@ -31,8 +37,156 @@ class EVPN(MPLSVPN, NLRI):

@classmethod
def parse(cls, nlri_data):
pass
nlri_list = []
while nlri_data:
route_type = ord(nlri_data[0])
offset = ord(nlri_data[1])
route_data = nlri_data[2: offset + 2]
if route_type == bgp_cons.BGPNLRI_EVPN_ETHERNET_AUTO_DISCOVERY:
pass
elif route_type == bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT:
route = MacIPAdvertisment.parse(route_data)
if route:
nlri_list.append({
'type': bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT,
'value': route
})
elif route_type == bgp_cons.BGPNLRI_EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
pass
elif route_type == bgp_cons.BGPNLRI_EVPN_ETHERNET_SEGMENT:
pass
nlri_data = nlri_data[offset + 2:]
return nlri_list

@classmethod
def construct(cls, nlri_list):
pass
nlri_list_hex = b''
for nlri in nlri_list:
if nlri['type'] == bgp_cons.BGPNLRI_EVPN_ETHERNET_AUTO_DISCOVERY:
pass
elif nlri['type'] == bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT:
nlri_hex = MacIPAdvertisment.construct(data=nlri['value'])
nlri_list_hex += struct.pack('!2B', bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT, len(nlri_hex)) \
+ nlri_hex
elif nlri['type'] == bgp_cons.BGPNLRI_EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
pass
elif nlri['type'] == bgp_cons.BGPNLRI_EVPN_ETHERNET_SEGMENT:
pass
return nlri_list_hex


class EthernetAutoDiscovery(MPLSVPN):
"""
+---------------------------------------+
| Route Distinguisher (RD) (8 octets) |
+---------------------------------------+
|Ethernet Segment Identifier (10 octets)|
+---------------------------------------+
| Ethernet Tag ID (4 octets) |
+---------------------------------------+
| MPLS Label (3 octets) |
+---------------------------------------+
"""


class MacIPAdvertisment(MPLSVPN):
"""
+---------------------------------------+
| RD (8 octets) |
+---------------------------------------+
|Ethernet Segment Identifier (10 octets)|
+---------------------------------------+
| Ethernet Tag ID (4 octets) |
+---------------------------------------+
| MAC Address Length (1 octet) |
+---------------------------------------+
| MAC Address (6 octets) |
+---------------------------------------+
| IP Address Length (1 octet) |
+---------------------------------------+
| IP Address (0, 4, or 16 octets) |
+---------------------------------------+
| MPLS Label1 (3 octets) |
+---------------------------------------+
| MPLS Label2 (0 or 3 octets) |
+---------------------------------------+
"""

@classmethod
def parse(cls, data):
route = dict()
# rd
offset = 8
route['rd'] = cls.parse_rd(data[0:offset])
# esi
route['esi'] = int(binascii.b2a_hex(data[offset: offset+10]), 16)
offset += 10
# ethernet tag id
route['ethernet_tag_id'] = struct.unpack('!I', data[offset: offset+4])[0]
offset += 5
# mac address
route['mac'] = str(netaddr.EUI(int(binascii.b2a_hex(data[offset: offset+6]), 16)))
offset += 6
ip_addr_len = ord(data[offset: offset + 1])
offset += 1
# ip address
if ip_addr_len != 0:
route['ip'] = str(netaddr.IPAddress(int(binascii.b2a_hex(data[offset: offset+ip_addr_len / 8]), 16)))
offset += ip_addr_len / 8
# label
route['label'] = MPLSVPN.parse_mpls_label_stack(data[offset:])
return route

@classmethod
def construct(cls, data):
# rd
data_hex = b''
data_hex += MPLSVPN.construct_rd(data['rd'])
# esi
data_hex += b'\x00\x00' + struct.pack('!d', data['esi'])
# ethernet tag
data_hex += struct.pack('!I', data['ethernet_tag_id'])
# mac address len and address
mac_hex = b''.join([struct.pack('!B', (int(i, 16))) for i in data['mac'].split("-")])
data_hex += struct.pack('!B', len(mac_hex) * 8) + mac_hex
# ip address len and address
if data.get('ip'):
ip_hex = netaddr.IPAddress(data['ip']).packed
data_hex += struct.pack('!B', len(ip_hex) * 8) + ip_hex
else:
data_hex += b'\x00'
if data.get('label'):
data_hex += MPLSVPN.construct_mpls_label_stack(data['label'], bos=False)
return data_hex


class InclusiveMulticastEthernetTag(MPLSVPN):
"""
+---------------------------------------+
| RD (8 octets) |
+---------------------------------------+
| Ethernet Tag ID (4 octets) |
+---------------------------------------+
| IP Address Length (1 octet) |
+---------------------------------------+
| Originating Router's IP Address |
| (4 or 16 octets) |
+---------------------------------------+
"""


class EthernetSegment(MPLSVPN):
"""
+---------------------------------------+
| RD (8 octets) |
+---------------------------------------+
|Ethernet Segment Identifier (10 octets)|
+---------------------------------------+
| IP Address Length (1 octet) |
+---------------------------------------+
| Originating Router's IP Address |
| (4 or 16 octets) |
+---------------------------------------+
"""
55 changes: 55 additions & 0 deletions yabgp/tests/unit/message/attribute/nlri/test_evpn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# 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.

import unittest

from yabgp.common import constants as bgp_cons
from yabgp.message.attribute.nlri.evpn import EVPN


class TestEVPN(unittest.TestCase):
def test_parse_mac_ip_adv(self):
data_hex = b'\x02\x25\x00\x01\xac\x11\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
b'\x00\x00\x00\x6c\x30\x00\x11\x22\x33\x44\x55\x20\x0b\x0b\x0b\x01\x00\x00\x00'
data_list = [{
'type': bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT,
'value': {
'rd': '172.17.0.3:2',
'mac': '00-11-22-33-44-55',
'ethernet_tag_id': 108,
'esi': 0,
'ip': '11.11.11.1',
'label': [0]}
}]
self.assertEqual(data_list, EVPN.parse(data_hex))

def test_construct_mac_ip_adv(self):
data_hex = b'\x02\x25\x00\x01\xac\x11\x00\x03\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' \
b'\x00\x00\x00\x6c\x30\x00\x11\x22\x33\x44\x55\x20\x0b\x0b\x0b\x01\x00\x00\x00'
data_list = [{
'type': bgp_cons.BGPNLRI_EVPN_MAC_IP_ADVERTISEMENT,
'value': {
'rd': '172.17.0.3:2',
'mac': '00-11-22-33-44-55',
'ethernet_tag_id': 108,
'esi': 0,
'ip': '11.11.11.1',
'label': [0]}
}]
self.assertEqual(data_hex, EVPN.construct(data_list))


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

0 comments on commit 3bbf54b

Please sign in to comment.